aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/pru/Makefile18
-rw-r--r--src/pru/internal.h37
-rw-r--r--src/pru/main.c96
-rw-r--r--src/pru/pru0.c (renamed from src/pru/console.c)157
-rw-r--r--src/pru/pru1.c29
5 files changed, 200 insertions, 137 deletions
diff --git a/src/pru/Makefile b/src/pru/Makefile
index 9cdb40c9..4e326955 100644
--- a/src/pru/Makefile
+++ b/src/pru/Makefile
@@ -6,22 +6,24 @@ CROSS_PREFIX=pru-
dirs-y += src/pru src/generic
dirs-y += lib/pru_rpmsg
-CFLAGS += -Os -mmcu=am335x.pru0
+CFLAGS += -Os -mmcu=am335x.pru1
CFLAGS += -Ilib/pru_rpmsg/include -Ilib/pru_rpmsg/include/am335x
CFLAGS_klipper.o := $(filter-out -mmcu=%, $(CFLAGS_klipper.o))
CFLAGS_klipper.elf := $(CFLAGS) -minrt -T src/pru/pru.lds
-CFLAGS_pru1.elf := $(filter-out -mmcu=%, $(CFLAGS)) -mmcu=am335x.pru1
+CFLAGS_pru0.elf := $(filter-out -mmcu=%, $(CFLAGS)) -minrt -mmcu=am335x.pru0
# Add source files
src-y := $(filter-out debugcmds.c, $(src-y))
-src-y += pru/main.c pru/console.c pru/gpio.c
+src-y += pru/main.c pru/gpio.c
src-y += generic/crc16_ccitt.c generic/timer_irq.c
-src-y += ../lib/pru_rpmsg/pru_rpmsg.c ../lib/pru_rpmsg/pru_virtqueue.c
-# Build the additional PRU1 binary
-target-y += $(OUT)pru1.elf
+pru0-y := pru/pru0.c
+pru0-y += ../lib/pru_rpmsg/pru_rpmsg.c ../lib/pru_rpmsg/pru_virtqueue.c
-$(OUT)pru1.elf: $(OUT)src/pru/pru1.o
+# Build the additional PRU0 binary
+target-y += $(OUT)pru0.elf
+
+$(OUT)pru0.elf: $(patsubst %.c, $(OUT)src/%.o,$(pru0-y))
@echo " Linking $@"
- $(Q)$(CC) $(CFLAGS_pru1.elf) $^ -o $@
+ $(Q)$(CC) $(CFLAGS_pru0.elf) $^ -o $@
diff --git a/src/pru/internal.h b/src/pru/internal.h
index b279f3d0..8556eed7 100644
--- a/src/pru/internal.h
+++ b/src/pru/internal.h
@@ -2,17 +2,38 @@
#define __PRU_INTERNAL_H
// Local definitions for PRU code
-#define IEP_IRQ 0
-#define GOT_ARM_IRQ 1
-#define WAKE_ARM_IRQ 2
+#include <stdint.h> // uint32_t
+
+#define IEP_EVENT 7
+#define KICK_ARM_EVENT 16
+#define KICK_PRU0_FROM_ARM_EVENT 17
+#define KICK_PRU0_EVENT 18
+#define KICK_PRU1_EVENT 19
-#define IEP_EVENT 7
-#define GOT_ARM_EVENT 17
-#define WAKE_ARM_EVENT 16
+#define WAKE_PRU0_IRQ 0
+#define WAKE_PRU1_IRQ 1
+#define WAKE_ARM_IRQ 2
#define R31_IRQ_OFFSET 30
-// console.c
-void console_init(void);
+#define R31_WRITE_IRQ_SELECT (1<<5)
+#define R31_WRITE_IRQ_OFFSET 16
+
+// Layout of shared memory
+struct shared_mem {
+ uint32_t signal;
+ uint32_t read_pos, read_count;
+ char read_data[512];
+ uint32_t send_push_pos, send_pop_pos;
+ struct {
+ uint32_t count;
+ char data[64];
+ } send_data[4];
+};
+
+#define SIGNAL_PRU0_WAITING 0xefefefef
+#define SIGNAL_PRU1_READY 0xabababab
+
+static struct shared_mem *SHARED_MEM = (void*)0x10000;
#endif // internal.h
diff --git a/src/pru/main.c b/src/pru/main.c
index c9c6422a..fcf66b39 100644
--- a/src/pru/main.c
+++ b/src/pru/main.c
@@ -7,15 +7,15 @@
#include <stdint.h> // uint32_t
#include <string.h> // memset
#include <pru/io.h> // read_r31
-#include <pru_cfg.h> // CT_CFG
#include <pru_iep.h> // CT_IEP
#include <pru_intc.h> // CT_INTC
-#include "autoconf.h" // CONFIG_CLOCK_FREQ
-#include "board/misc.h" // timer_from_us
+#include <rsc_types.h> // resource_table
+#include "board/misc.h" // alloc_chunk
+#include "board/io.h" // readl
#include "board/irq.h" // irq_disable
#include "command.h" // shutdown
#include "generic/timer_irq.h" // timer_dispatch_many
-#include "internal.h" // IEP_IRQ
+#include "internal.h" // SHARED_MEM
#include "sched.h" // sched_main
DECL_CONSTANT(MCU, "pru");
@@ -50,7 +50,6 @@ static void
timer_set(uint32_t value)
{
CT_IEP.TMR_CMP0 = value;
- CT_INTC.SECR0 = 1 << IEP_EVENT;
}
uint32_t
@@ -62,14 +61,17 @@ timer_read_time(void)
static void
_irq_poll(void)
{
- CT_IEP.TMR_CMP_STS = 0xff;
- uint32_t next = timer_dispatch_many();
- timer_set(next);
+ if (CT_INTC.SECR0 & (1 << IEP_EVENT)) {
+ CT_IEP.TMR_CMP_STS = 0xff;
+ uint32_t next = timer_dispatch_many();
+ timer_set(next);
+ }
+ CT_INTC.SECR0 = (1 << IEP_EVENT) | (1 << KICK_PRU1_EVENT);
}
void
irq_poll(void)
{
- if (read_r31() & (1 << (IEP_IRQ + R31_IRQ_OFFSET)))
+ if (read_r31() & (1 << (WAKE_PRU1_IRQ + R31_IRQ_OFFSET)))
_irq_poll();
}
@@ -87,7 +89,7 @@ DECL_SHUTDOWN(timer_shutdown);
static void
timer_init(void)
{
- timer_set(0);
+ CT_IEP.TMR_CNT = 0;
CT_IEP.TMR_CMP_CFG = 0x01 << 1;
CT_IEP.TMR_GLB_CFG = 0x11;
timer_shutdown();
@@ -95,6 +97,55 @@ timer_init(void)
/****************************************************************
+ * Console IO
+ ****************************************************************/
+
+// Return a buffer (and length) containing any incoming messages
+char *
+console_get_input(uint8_t *plen)
+{
+ uint32_t read_count = readl(&SHARED_MEM->read_count);
+ if (read_count > 64)
+ read_count = 64;
+ *plen = read_count;
+ return SHARED_MEM->read_data;
+}
+
+// Remove from the receive buffer the given number of bytes
+void
+console_pop_input(uint8_t len)
+{
+ barrier();
+ writel(&SHARED_MEM->read_count, 0);
+}
+
+// Return an output buffer that the caller may fill with transmit messages
+char *
+console_get_output(uint8_t len)
+{
+ if (len > sizeof(SHARED_MEM->send_data[0].data))
+ return NULL;
+ uint32_t send_push_pos = SHARED_MEM->send_push_pos;
+ if (readl(&SHARED_MEM->send_data[send_push_pos].count))
+ // Queue full
+ return NULL;
+ return SHARED_MEM->send_data[send_push_pos].data;
+}
+
+// Accept the given number of bytes added to the transmit buffer
+void
+console_push_output(uint8_t len)
+{
+ uint32_t send_push_pos = SHARED_MEM->send_push_pos;
+ barrier();
+ writel(&SHARED_MEM->send_data[send_push_pos].count, len);
+ write_r31(R31_WRITE_IRQ_SELECT | (KICK_PRU0_EVENT - R31_WRITE_IRQ_OFFSET));
+ SHARED_MEM->send_push_pos = (
+ (send_push_pos + 1) % ARRAY_SIZE(SHARED_MEM->send_data));
+}
+
+
+/****************************************************************
* Allocator
****************************************************************/
@@ -132,6 +183,24 @@ alloc_chunks(size_t size, size_t count, size_t *avail)
/****************************************************************
+ * Resource table
+ ****************************************************************/
+
+struct my_resource_table {
+ struct resource_table base;
+
+ uint32_t offset[1]; /* Should match 'num' in actual definition */
+} resourceTable __visible __section(".resource_table") = {
+ {
+ 1, /* Resource table version: only version 1 is
+ * supported by the current driver */
+ 0, /* number of entries in the table */
+ { 0, 0 }, /* reserved, must be zero */
+ },
+};
+
+
+/****************************************************************
* Startup
****************************************************************/
@@ -139,10 +208,11 @@ alloc_chunks(size_t size, size_t count, size_t *avail)
int
main(void)
{
- // allow access to external memory
- CT_CFG.SYSCFG_bit.STANDBY_INIT = 0;
+ // Wait for PRU0 to initialize
+ while (readl(&SHARED_MEM->signal) != SIGNAL_PRU0_WAITING)
+ ;
+ writel(&SHARED_MEM->signal, SIGNAL_PRU1_READY);
- console_init();
timer_init();
sched_main();
diff --git a/src/pru/console.c b/src/pru/pru0.c
index c22e6c82..e4bd1c46 100644
--- a/src/pru/console.c
+++ b/src/pru/pru0.c
@@ -1,101 +1,83 @@
-// PRU input/output via RPMsg
+// Code to handle IO on PRU0 and pass the messages to PRU1
//
// Copyright (C) 2017 Kevin O'Connor <kevin@koconnor.net>
//
// This file may be distributed under the terms of the GNU GPLv3 license.
#include <stdint.h> // uint32_t
-#include <string.h> // memcpy
-#include <pru/io.h> // read_r31
+#include <string.h> // memset
+#include <pru/io.h> // write_r31
+#include <pru_cfg.h> // CT_CFG
#include <pru_intc.h> // CT_INTC
#include <pru_rpmsg.h> // pru_rpmsg_send
#include <pru_virtio_ids.h> // VIRTIO_ID_RPMSG
-#include "board/misc.h" // console_get_input
-#include "internal.h" // WAKE_ARM_EVENT
-#include "sched.h" // DECL_INIT
-
-#define CHAN_NAME "rpmsg-pru"
-#define CHAN_DESC "Channel 30"
-#define CHAN_PORT 30
+#include <rsc_types.h> // resource_table
+#include "board/io.h" // readl
+#include "compiler.h" // __section
+#include "internal.h" // SHARED_MEM
/****************************************************************
- * Console interface
+ * IO
****************************************************************/
-static void
-clear_pending(void)
-{
- CT_INTC.SECR0 = 1 << GOT_ARM_EVENT;
-}
+#define CHAN_NAME "rpmsg-pru"
+#define CHAN_DESC "Channel 30"
+#define CHAN_PORT 30
-static struct pru_rpmsg_transport transport;
static uint16_t transport_dst;
-static char input_data[64];
-
-// XXX
-struct pru_rpmsg_hdr {
- uint32_t src;
- uint32_t dst;
- uint32_t reserved;
- uint16_t len;
- uint16_t flags;
- uint8_t data[0];
-};
-// Return a buffer (and length) containing any incoming messages
-char *
-console_get_input(uint8_t *plen)
+static void
+check_can_send(struct pru_rpmsg_transport *transport)
{
- if (!(read_r31() & (1 << (GOT_ARM_IRQ + R31_IRQ_OFFSET))))
- goto nodata;
- struct pru_rpmsg_hdr *msg;
- uint32_t msg_len;
- int16_t head = pru_virtqueue_get_avail_buf(
- &transport.virtqueue1, (void**)&msg, &msg_len);
- if (head < 0) {
- clear_pending();
- goto nodata;
+ for (;;) {
+ uint32_t send_pop_pos = SHARED_MEM->send_pop_pos;
+ uint32_t count = readl(&SHARED_MEM->send_data[send_pop_pos].count);
+ if (!count)
+ // Queue empty
+ break;
+ pru_rpmsg_send(
+ transport, CHAN_PORT, transport_dst
+ , &SHARED_MEM->send_data[send_pop_pos].data, count);
+ barrier();
+ writel(&SHARED_MEM->send_data[send_pop_pos].count, 0);
+ SHARED_MEM->send_pop_pos = (
+ (send_pop_pos + 1) % ARRAY_SIZE(SHARED_MEM->send_data));
}
- transport_dst = msg->src;
- int len = msg->len < sizeof(input_data) ? msg->len : sizeof(input_data);
- memcpy(input_data, msg->data, len);
- pru_virtqueue_add_used_buf(&transport.virtqueue1, head, msg_len);
- pru_virtqueue_kick(&transport.virtqueue1);
- *plen = len;
- return input_data;
-nodata:
- *plen = 0;
- return input_data;
-}
-
-// Remove from the receive buffer the given number of bytes
-void
-console_pop_input(uint8_t len)
-{
}
-static char output_data[64];
-
-// Return an output buffer that the caller may fill with transmit messages
-char *
-console_get_output(uint8_t len)
+static void
+check_can_read(struct pru_rpmsg_transport *transport)
{
- if (len > sizeof(output_data))
- return NULL;
- return output_data;
+ if (readl(&SHARED_MEM->read_count))
+ // main processing pru is busy
+ return;
+ uint16_t dst, len;
+ int16_t ret = pru_rpmsg_receive(
+ transport, &transport_dst, &dst, SHARED_MEM->read_data, &len);
+ if (ret || !len)
+ return;
+ SHARED_MEM->read_pos = 0;
+ barrier();
+ writel(&SHARED_MEM->read_count, len);
+ write_r31(R31_WRITE_IRQ_SELECT | (KICK_PRU1_EVENT - R31_WRITE_IRQ_OFFSET));
}
-// Accept the given number of bytes added to the transmit buffer
-void
-console_push_output(uint8_t len)
+static void
+process_io(struct pru_rpmsg_transport *transport)
{
- pru_rpmsg_send(&transport, CHAN_PORT, transport_dst, output_data, len);
+ for (;;) {
+ if (!(read_r31() & (1 << (WAKE_PRU0_IRQ + R31_IRQ_OFFSET))))
+ continue;
+ CT_INTC.SECR0 = (1 << KICK_PRU0_FROM_ARM_EVENT) | (1 << KICK_PRU0_EVENT);
+ check_can_send(transport);
+ check_can_read(transport);
+ }
}
/****************************************************************
- * resource table
+ * Resource table
****************************************************************/
/*
@@ -118,9 +100,11 @@ console_push_output(uint8_t len)
/* Mapping sysevts to a channel. Each pair contains a sysevt, channel. */
static struct ch_map pru_intc_map[] = {
- {IEP_EVENT, IEP_IRQ},
- {WAKE_ARM_EVENT, WAKE_ARM_IRQ},
- {GOT_ARM_EVENT, GOT_ARM_IRQ},
+ {IEP_EVENT, WAKE_PRU1_IRQ},
+ {KICK_ARM_EVENT, WAKE_ARM_IRQ},
+ {KICK_PRU0_FROM_ARM_EVENT, WAKE_PRU0_IRQ},
+ {KICK_PRU0_EVENT, WAKE_PRU0_IRQ},
+ {KICK_PRU1_EVENT, WAKE_PRU1_IRQ},
};
struct my_resource_table {
@@ -185,7 +169,7 @@ struct my_resource_table {
0x0000,
/* Channel-to-host mapping, 255 for unused */
{
- IEP_IRQ, GOT_ARM_IRQ, WAKE_ARM_IRQ,
+ WAKE_PRU0_IRQ, WAKE_PRU1_IRQ, WAKE_ARM_IRQ,
HOST_UNUSED, HOST_UNUSED, HOST_UNUSED,
HOST_UNUSED, HOST_UNUSED, HOST_UNUSED, HOST_UNUSED
},
@@ -200,15 +184,20 @@ struct my_resource_table {
/****************************************************************
- * RPMsg init
+ * Startup
****************************************************************/
#define VIRTIO_CONFIG_S_DRIVER_OK 4
-void
-console_init(void)
+int
+main(void)
{
- clear_pending();
+ // allow access to external memory
+ CT_CFG.SYSCFG_bit.STANDBY_INIT = 0;
+
+ // clear all irqs
+ CT_INTC.SECR0 = 0xffffffff;
+ CT_INTC.SECR1 = 0xffffffff;
/* Make sure the Linux drivers are ready for RPMsg communication */
volatile uint8_t *status = &resourceTable.rpmsg_vdev.status;
@@ -216,15 +205,25 @@ console_init(void)
;
/* Initialize the RPMsg transport structure */
+ struct pru_rpmsg_transport transport;
pru_rpmsg_init(&transport,
&resourceTable.rpmsg_vring0,
&resourceTable.rpmsg_vring1,
- WAKE_ARM_EVENT,
- GOT_ARM_EVENT);
+ KICK_ARM_EVENT,
+ KICK_PRU0_FROM_ARM_EVENT);
/* Create the RPMsg channel between the PRU and ARM user space
* using the transport structure. */
while (pru_rpmsg_channel(RPMSG_NS_CREATE, &transport, CHAN_NAME
, CHAN_DESC, CHAN_PORT) != PRU_RPMSG_SUCCESS)
;
+
+ // Wait for PRU1 to be ready
+ memset(SHARED_MEM, 0, sizeof(*SHARED_MEM));
+ writel(&SHARED_MEM->signal, SIGNAL_PRU0_WAITING);
+ while (readl(&SHARED_MEM->signal) != SIGNAL_PRU1_READY)
+ ;
+ writel(&SHARED_MEM->signal, 0);
+
+ process_io(&transport);
}
diff --git a/src/pru/pru1.c b/src/pru/pru1.c
deleted file mode 100644
index 3a850a60..00000000
--- a/src/pru/pru1.c
+++ /dev/null
@@ -1,29 +0,0 @@
-// Code to halt the unneeded PRU1
-//
-// Copyright (C) 2017 Kevin O'Connor <kevin@koconnor.net>
-//
-// This file may be distributed under the terms of the GNU GPLv3 license.
-
-#include <stdint.h> // uint32_t
-#include <pru/io.h> // __halt
-#include <rsc_types.h> // resource_table
-#include "compiler.h" // __section
-
-struct my_resource_table {
- struct resource_table base;
-
- uint32_t offset[1]; /* Should match 'num' in actual definition */
-} resourceTable __section(".resource_table") = {
- {
- 1, /* Resource table version: only version 1 is
- * supported by the current driver */
- 0, /* number of entries in the table */
- { 0, 0 }, /* reserved, must be zero */
- },
-};
-
-int
-main(void)
-{
- __halt();
-}