From b85755c0ff4cb31aeafc9fd0abd63094508d731b Mon Sep 17 00:00:00 2001 From: Kevin O'Connor Date: Tue, 16 May 2017 13:41:44 -0400 Subject: [PATCH] pru: Move communication code to second PRU Perform input and output in the second PRU so that more space is available in the primary PRU. Signed-off-by: Kevin O'Connor --- src/pru/Makefile | 18 ++-- src/pru/internal.h | 37 ++++++-- src/pru/main.c | 96 +++++++++++++++++--- src/pru/{console.c => pru0.c} | 159 +++++++++++++++++----------------- src/pru/pru1.c | 29 ------- 5 files changed, 201 insertions(+), 138 deletions(-) rename src/pru/{console.c => pru0.c} (66%) delete mode 100644 src/pru/pru1.c 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 // uint32_t -#define IEP_EVENT 7 -#define GOT_ARM_EVENT 17 -#define WAKE_ARM_EVENT 16 +#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 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 // uint32_t #include // memset #include // read_r31 -#include // CT_CFG #include // CT_IEP #include // CT_INTC -#include "autoconf.h" // CONFIG_CLOCK_FREQ -#include "board/misc.h" // timer_from_us +#include // 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,13 +89,62 @@ 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(); } +/**************************************************************** + * 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 ****************************************************************/ @@ -131,6 +182,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 similarity index 66% rename from src/pru/console.c rename to 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 // // This file may be distributed under the terms of the GNU GPLv3 license. #include // uint32_t -#include // memcpy -#include // read_r31 +#include // memset +#include // write_r31 +#include // CT_CFG #include // CT_INTC #include // pru_rpmsg_send #include // VIRTIO_ID_RPMSG -#include "board/misc.h" // console_get_input -#include "internal.h" // WAKE_ARM_EVENT -#include "sched.h" // DECL_INIT +#include // resource_table +#include "board/io.h" // readl +#include "compiler.h" // __section +#include "internal.h" // SHARED_MEM + + +/**************************************************************** + * IO + ****************************************************************/ #define CHAN_NAME "rpmsg-pru" #define CHAN_DESC "Channel 30" #define CHAN_PORT 30 - -/**************************************************************** - * Console interface - ****************************************************************/ +static uint16_t transport_dst; static void -clear_pending(void) +check_can_send(struct pru_rpmsg_transport *transport) { - CT_INTC.SECR0 = 1 << GOT_ARM_EVENT; -} - -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) -{ - 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 void +check_can_read(struct pru_rpmsg_transport *transport) { + 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)); } -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 +process_io(struct pru_rpmsg_transport *transport) { - if (len > sizeof(output_data)) - return NULL; - return output_data; -} - -// Accept the given number of bytes added to the transmit buffer -void -console_push_output(uint8_t len) -{ - 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 -// -// This file may be distributed under the terms of the GNU GPLv3 license. - -#include // uint32_t -#include // __halt -#include // 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(); -}