aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/command.c20
-rw-r--r--src/command.h15
-rw-r--r--src/pru/Makefile17
-rw-r--r--src/pru/internal.h10
-rw-r--r--src/pru/main.c92
-rw-r--r--src/pru/pru0.c153
6 files changed, 214 insertions, 93 deletions
diff --git a/src/command.c b/src/command.c
index af84539f..53263a8f 100644
--- a/src/command.c
+++ b/src/command.c
@@ -13,19 +13,6 @@
#include "command.h" // output_P
#include "sched.h" // DECL_TASK
-#define MESSAGE_MIN 5
-#define MESSAGE_MAX 64
-#define MESSAGE_HEADER_SIZE 2
-#define MESSAGE_TRAILER_SIZE 3
-#define MESSAGE_POS_LEN 0
-#define MESSAGE_POS_SEQ 1
-#define MESSAGE_TRAILER_CRC 3
-#define MESSAGE_TRAILER_SYNC 1
-#define MESSAGE_PAYLOAD_MAX (MESSAGE_MAX - MESSAGE_MIN)
-#define MESSAGE_SEQ_MASK 0x0f
-#define MESSAGE_DEST 0x10
-#define MESSAGE_SYNC 0x7E
-
static uint8_t next_sequence = MESSAGE_DEST;
@@ -68,8 +55,9 @@ parse_int(char **pp)
}
// Parse an incoming command into 'args'
-static char *
-parsef(char *p, char *maxend, const struct command_parser *cp, uint32_t *args)
+char *
+command_parsef(char *p, char *maxend
+ , const struct command_parser *cp, uint32_t *args)
{
uint8_t num_params = READP(cp->num_params);
const uint8_t *param_types = READP(cp->param_types);
@@ -301,7 +289,7 @@ command_dispatch(char *buf, uint8_t msglen)
uint8_t cmdid = *p++;
const struct command_parser *cp = command_lookup_parser(cmdid);
uint32_t args[READP(cp->num_args)];
- p = parsef(p, msgend, cp, args);
+ p = command_parsef(p, msgend, cp, args);
if (sched_is_shutdown() && !(READP(cp->flags) & HF_IN_SHUTDOWN)) {
sched_report_shutdown();
continue;
diff --git a/src/command.h b/src/command.h
index 148f47be..91d7cd80 100644
--- a/src/command.h
+++ b/src/command.h
@@ -33,6 +33,19 @@
#define try_shutdown(msg) \
sched_try_shutdown(_DECL_STATIC_STR(msg))
+#define MESSAGE_MIN 5
+#define MESSAGE_MAX 64
+#define MESSAGE_HEADER_SIZE 2
+#define MESSAGE_TRAILER_SIZE 3
+#define MESSAGE_POS_LEN 0
+#define MESSAGE_POS_SEQ 1
+#define MESSAGE_TRAILER_CRC 3
+#define MESSAGE_TRAILER_SYNC 1
+#define MESSAGE_PAYLOAD_MAX (MESSAGE_MAX - MESSAGE_MIN)
+#define MESSAGE_SEQ_MASK 0x0f
+#define MESSAGE_DEST 0x10
+#define MESSAGE_SYNC 0x7E
+
struct command_encoder {
uint8_t msg_id, max_size, num_params;
const uint8_t *param_types;
@@ -48,6 +61,8 @@ enum {
};
// command.c
+char *command_parsef(char *p, char *maxend
+ , const struct command_parser *cp, uint32_t *args);
uint8_t command_encodef(char *buf, uint8_t buf_len
, const struct command_encoder *ce, va_list args);
void command_sendf(const struct command_encoder *ce, ...);
diff --git a/src/pru/Makefile b/src/pru/Makefile
index 5f5739b4..a5dfaeb8 100644
--- a/src/pru/Makefile
+++ b/src/pru/Makefile
@@ -6,28 +6,27 @@ CROSS_PREFIX=pru-
dirs-y += src/pru src/generic
dirs-y += lib/pru_rpmsg
-CFLAGS += -Os -mmcu=am335x.pru1
+CFLAGS += -minrt -mmcu=am335x.pru1
CFLAGS += -Ilib/pru_rpmsg/include -Ilib/pru_rpmsg/include/am335x
CFLAGS_klipper.elf := $(filter-out -mmcu=%, $(CFLAGS))
CFLAGS_klipper.elf += -Wl,-r -nostdlib -Wl,-T,src/pru/pru.lds
-CFLAGS_pru0.elf := $(filter-out -mmcu=%, $(CFLAGS)) -minrt -mmcu=am335x.pru0
-CFLAGS_pru1.elf := $(CFLAGS) -minrt
+CFLAGS_pru0.elf := $(filter-out -mmcu=%, $(CFLAGS)) -mmcu=am335x.pru0
+CFLAGS_pru1.elf := $(CFLAGS)
# Add source files
-src-y := $(filter-out debugcmds.c, $(src-y))
-src-y += pru/main.c pru/gpio.c
-src-y += generic/crc16_ccitt.c generic/timer_irq.c
+src-y += pru/main.c pru/gpio.c generic/timer_irq.c
-pru0-y := pru/pru0.c
+pru0-y := pru/pru0.c generic/crc16_ccitt.c command.c
pru0-y += ../lib/pru_rpmsg/pru_rpmsg.c ../lib/pru_rpmsg/pru_virtqueue.c
-# Build the additional PRU0 binary
+# Build the PRU binaries
target-y += $(OUT)pru0.elf $(OUT)pru1.elf
$(OUT)pru0.elf: $(patsubst %.c, $(OUT)src/%.o,$(pru0-y))
@echo " Linking $@"
- $(Q)$(CC) $(CFLAGS_pru0.elf) $^ -o $@
+ $(Q)$(CC) $(CFLAGS_klipper.elf) $^ -o $(OUT)pru0.o
+ $(Q)$(CC) $(CFLAGS_pru0.elf) $(OUT)pru0.o -o $@
$(OUT)pru1.elf: $(OUT)klipper.elf
@echo " Linking $@"
diff --git a/src/pru/internal.h b/src/pru/internal.h
index 109dd3a2..1a2983d2 100644
--- a/src/pru/internal.h
+++ b/src/pru/internal.h
@@ -19,16 +19,22 @@
#define R31_WRITE_IRQ_SELECT (1<<5)
#define R31_WRITE_IRQ_OFFSET 16
+#define ALT_PRU_PTR(ptr) ((typeof(ptr))((uint32_t)(ptr) ^ 0x2000))
+
// Layout of shared memory
struct shared_mem {
uint32_t signal;
- uint32_t read_pos, read_count;
- char read_data[512];
+ const struct command_parser *next_command;
+ uint32_t next_command_args[16];
uint32_t send_push_pos, send_pop_pos;
struct {
uint32_t count;
char data[64];
} send_data[4];
+ const struct command_parser *command_index;
+ uint32_t command_index_size;
+ const struct command_parser *shutdown_handler;
+ char read_data[512];
};
#define SIGNAL_PRU0_WAITING 0xefefefef
diff --git a/src/pru/main.c b/src/pru/main.c
index d906b1ad..ea0ec602 100644
--- a/src/pru/main.c
+++ b/src/pru/main.c
@@ -99,73 +99,68 @@ DECL_INIT(timer_init);
* Console IO
****************************************************************/
-// Return a buffer (and length) containing any incoming messages
-static 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
-static void
-console_pop_input(uint8_t len)
-{
- writel(&SHARED_MEM->read_count, 0);
-}
-
// Process any incoming commands
void
console_task(void)
{
- uint8_t buf_len, pop_count;
- char *buf = console_get_input(&buf_len);
- int8_t ret = command_find_block(buf, buf_len, &pop_count);
- if (ret)
- command_dispatch(buf, pop_count);
- console_pop_input(pop_count);
+ const struct command_parser *cp = SHARED_MEM->next_command;
+ if (!cp)
+ return;
+ barrier();
+
+ if (sched_is_shutdown() && !(cp->flags & HF_IN_SHUTDOWN)) {
+ sched_report_shutdown();
+ } else {
+ void (*func)(uint32_t*) = cp->func;
+ func(SHARED_MEM->next_command_args);
+ }
+
+ writel(&SHARED_MEM->next_command, 0);
}
DECL_TASK(console_task);
-// Return an output buffer that the caller may fill with transmit messages
-static char *
-console_get_output(uint8_t len)
+// Encode and transmit a "response" message
+void
+console_sendf(const struct command_encoder *ce, va_list args)
{
- if (len > sizeof(SHARED_MEM->send_data[0].data))
- return NULL;
+ // Verify space for message
+ uint32_t max_size = ce->max_size;
+ if (max_size > sizeof(SHARED_MEM->send_data[0].data))
+ return;
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;
-}
+ return;
-// Accept the given number of bytes added to the transmit buffer
-static void
-console_push_output(uint8_t len)
-{
- uint32_t send_push_pos = SHARED_MEM->send_push_pos;
- writel(&SHARED_MEM->send_data[send_push_pos].count, len);
+ // Generate message
+ char *buf = SHARED_MEM->send_data[send_push_pos].data;
+ uint32_t msglen = command_encodef(buf, max_size, ce, args);
+
+ // Signal PRU0 to transmit message
+ writel(&SHARED_MEM->send_data[send_push_pos].count, msglen);
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));
}
-// Encode and transmit a "response" message
void
-console_sendf(const struct command_encoder *ce, va_list args)
+console_shutdown(void)
{
- uint8_t buf_len = ce->max_size;
- char *buf = console_get_output(buf_len);
- if (!buf)
- return;
- uint8_t msglen = command_encodef(buf, buf_len, ce, args);
- command_add_frame(buf, msglen);
- console_push_output(msglen);
+ writel(&SHARED_MEM->next_command, 0);
}
+DECL_SHUTDOWN(console_shutdown);
+
+// Handle shutdown request from PRU0
+static void
+shutdown_handler(uint32_t *args)
+{
+ shutdown("Request from PRU0");
+}
+
+// Empty message (for ack/nak transmission)
+const struct command_parser shutdown_request = {
+ .func = shutdown_handler,
+};
/****************************************************************
@@ -234,6 +229,9 @@ main(void)
// Wait for PRU0 to initialize
while (readl(&SHARED_MEM->signal) != SIGNAL_PRU0_WAITING)
;
+ SHARED_MEM->command_index = command_index;
+ SHARED_MEM->command_index_size = command_index_size;
+ SHARED_MEM->shutdown_handler = &shutdown_request;
writel(&SHARED_MEM->signal, SIGNAL_PRU1_READY);
sched_main();
diff --git a/src/pru/pru0.c b/src/pru/pru0.c
index 424ba5c6..6ea42287 100644
--- a/src/pru/pru0.c
+++ b/src/pru/pru0.c
@@ -4,6 +4,7 @@
//
// This file may be distributed under the terms of the GNU GPLv3 license.
+#include <setjmp.h> // setjmp
#include <stdint.h> // uint32_t
#include <string.h> // memset
#include <pru/io.h> // write_r31
@@ -14,8 +15,13 @@
#include <pru_virtio_ids.h> // VIRTIO_ID_RPMSG
#include <rsc_types.h> // resource_table
#include "board/io.h" // readl
+#include "command.h" // command_add_frame
#include "compiler.h" // __section
#include "internal.h" // SHARED_MEM
+#include "sched.h" // sched_shutdown
+
+struct pru_rpmsg_transport transport;
+static uint16_t transport_dst;
/****************************************************************
@@ -26,10 +32,9 @@
#define CHAN_DESC "Channel 30"
#define CHAN_PORT 30
-static uint16_t transport_dst;
-
+// Check if there is data to be sent from PRU1 to the host
static void
-check_can_send(struct pru_rpmsg_transport *transport)
+check_can_send(void)
{
for (;;) {
uint32_t send_pop_pos = SHARED_MEM->send_pop_pos;
@@ -37,8 +42,9 @@ check_can_send(struct pru_rpmsg_transport *transport)
if (!count)
// Queue empty
break;
+ command_add_frame(SHARED_MEM->send_data[send_pop_pos].data, count);
pru_rpmsg_send(
- transport, CHAN_PORT, transport_dst
+ &transport, CHAN_PORT, transport_dst
, &SHARED_MEM->send_data[send_pop_pos].data, count);
writel(&SHARED_MEM->send_data[send_pop_pos].count, 0);
SHARED_MEM->send_pop_pos = (
@@ -46,34 +52,135 @@ check_can_send(struct pru_rpmsg_transport *transport)
}
}
+// Wait for PRU1 to finish processing a command
static void
-check_can_read(struct pru_rpmsg_transport *transport)
+wait_pru1_command(void)
{
- if (readl(&SHARED_MEM->read_count))
- // main processing pru is busy
- return;
+ while (readl(&SHARED_MEM->next_command))
+ check_can_send();
+ check_can_send();
+}
+
+// Signal PRU1 that a new command is ready
+static void
+send_pru1_command(const struct command_parser *cp)
+{
+ barrier();
+ SHARED_MEM->next_command = cp;
+ barrier();
+ write_r31(R31_WRITE_IRQ_SELECT | (KICK_PRU1_EVENT - R31_WRITE_IRQ_OFFSET));
+}
+
+// Instruct PRU1 to shutdown
+static void
+send_pru1_shutdown(void)
+{
+ wait_pru1_command();
+ send_pru1_command(SHARED_MEM->shutdown_handler);
+ wait_pru1_command();
+}
+
+// Dispatch all the commands in a message block
+static void
+do_dispatch(char *buf, uint32_t msglen)
+{
+ char *p = &buf[MESSAGE_HEADER_SIZE];
+ char *msgend = &buf[msglen-MESSAGE_TRAILER_SIZE];
+ while (p < msgend) {
+ // Parse command
+ uint8_t cmdid = *p++;
+ const struct command_parser *cp = &SHARED_MEM->command_index[cmdid];
+ if (!cmdid || cmdid >= SHARED_MEM->command_index_size
+ || cp->num_args > ARRAY_SIZE(SHARED_MEM->next_command_args)) {
+ send_pru1_shutdown();
+ return;
+ }
+ p = command_parsef(p, msgend, cp, SHARED_MEM->next_command_args);
+
+ send_pru1_command(ALT_PRU_PTR(cp));
+ wait_pru1_command();
+ }
+}
+
+// See if there are commands from the host ready to be processed
+static void
+check_can_read(void)
+{
+ // Read data
uint16_t dst, len;
- int16_t ret = pru_rpmsg_receive(
- transport, &transport_dst, &dst, SHARED_MEM->read_data, &len);
- if (ret || !len)
+ char *p = SHARED_MEM->read_data;
+ int16_t ret = pru_rpmsg_receive(&transport, &transport_dst, &dst, p, &len);
+ if (ret)
return;
- SHARED_MEM->read_pos = 0;
- writel(&SHARED_MEM->read_count, len);
- write_r31(R31_WRITE_IRQ_SELECT | (KICK_PRU1_EVENT - R31_WRITE_IRQ_OFFSET));
+
+ // Parse data into message blocks
+ for (;;) {
+ uint8_t pop_count, msglen = len > 64 ? 64 : len;
+ int8_t ret = command_find_block(p, msglen, &pop_count);
+ if (!ret)
+ break;
+ if (ret > 0)
+ do_dispatch(p, pop_count);
+ p += pop_count;
+ len -= pop_count;
+ }
}
+// Main processing loop
static void
-process_io(struct pru_rpmsg_transport *transport)
+process_io(void)
{
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);
+ check_can_send();
+ check_can_read();
}
}
+// Startup initialization
+static void
+setup_io(void)
+{
+ // Fixup pointers in command_parsers
+ SHARED_MEM->command_index = ALT_PRU_PTR(SHARED_MEM->command_index);
+ struct command_parser *p = (void*)SHARED_MEM->command_index;
+ int i;
+ for (i=0; i<SHARED_MEM->command_index_size; i++, p++)
+ if (p->param_types)
+ p->param_types = ALT_PRU_PTR(p->param_types);
+}
+
+
+/****************************************************************
+ * Compatibility wrappers
+ ****************************************************************/
+
+// shutdown() compatibility code
+uint8_t ctr_lookup_static_string(const char *str)
+{
+ return 0;
+}
+
+static jmp_buf shutdown_jmp;
+
+// Handle shutdown()
+void
+sched_shutdown(uint_fast8_t reason)
+{
+ longjmp(shutdown_jmp, 1);
+}
+
+// Generate messages - only used for ack/nak messages
+void
+console_sendf(const struct command_encoder *ce, va_list args)
+{
+ char buf[MESSAGE_MIN];
+ command_add_frame(buf, sizeof(buf));
+ pru_rpmsg_send(&transport, CHAN_PORT, transport_dst, buf, sizeof(buf));
+}
+
/****************************************************************
* Peripheral reset
@@ -241,7 +348,6 @@ main(void)
;
/* Initialize the RPMsg transport structure */
- struct pru_rpmsg_transport transport;
pru_rpmsg_init(&transport,
&resourceTable.rpmsg_vring0,
&resourceTable.rpmsg_vring1,
@@ -265,5 +371,14 @@ main(void)
;
writel(&SHARED_MEM->signal, 0);
- process_io(&transport);
+ // Setup incoming message parser
+ setup_io();
+
+ // Support shutdown
+ int ret = setjmp(shutdown_jmp);
+ if (ret)
+ send_pru1_shutdown();
+
+ // Main loop
+ process_io();
}