diff options
author | Marc Zyngier <maz@kernel.org> | 2023-08-27 10:28:11 +0100 |
---|---|---|
committer | Marc Zyngier <maz@kernel.org> | 2023-08-27 10:32:57 +0100 |
commit | 1a4c59587137f6a2ebb32ecf6393110402b04d61 (patch) | |
tree | e8d8ab105f6087f2154a4da67b0232e6adff6378 | |
parent | 0a4652cd6fff2bfdfc223f2a0ef4d6e4d1bdb3ad (diff) | |
download | cs-sw-1a4c59587137f6a2ebb32ecf6393110402b04d61.tar.gz |
Add primitive support for serial1 as the upstream port
Signed-off-by: Marc Zyngier <maz@kernel.org>
-rw-r--r-- | m1-pd-bmc.h | 2 | ||||
-rw-r--r-- | start.c | 76 | ||||
-rw-r--r-- | vdmtool.c | 27 |
3 files changed, 100 insertions, 5 deletions
diff --git a/m1-pd-bmc.h b/m1-pd-bmc.h index 6edc509..616b6d8 100644 --- a/m1-pd-bmc.h +++ b/m1-pd-bmc.h @@ -52,6 +52,8 @@ struct upstream_ops { }; extern const struct upstream_ops *upstream_ops; +void set_upstream_ops(bool serial); +bool upstream_is_serial(void); void upstream_tx_str(int32_t port, const char *ptr); @@ -96,6 +96,16 @@ static const struct gpio_pin_config m1_pd_bmc_pin_config1[] = { }, }; +static struct { + /* + * we rely on prod/cons rollover behaviour, and buf must cover + * the full range of prod/cons. + */ + uint8_t prod; + uint8_t cons; + char buf[256]; +} uart1_buf; + static void __not_in_flash_func(uart_irq_fn)(int port, const struct hw_context *hw) { @@ -135,7 +145,18 @@ static void __not_in_flash_func(uart0_irq_fn)(void) static void __not_in_flash_func(uart1_irq_fn)(void) { - uart_irq_fn(1, &hw1); + if (!upstream_is_serial()) { + uart_irq_fn(1, &hw1); + return; + } + + while (uart_is_readable(uart1)) { + uart1_buf.buf[uart1_buf.prod++] = uart_getc(uart1); + + /* Oops, we're losing data... */ + if (uart1_buf.prod == uart1_buf.cons) + uart1_buf.cons++; + } } static void init_system(const struct hw_context *hw) @@ -217,6 +238,41 @@ static const struct upstream_ops usb_upstream_ops = { .flush = tud_task, }; +static void serial1_tx_bytes(int32_t port, const char *ptr, int len) +{ + uart_write_blocking(uart1, ptr, len); +} + +static int32_t serial1_rx_byte(int32_t port) +{ + uint32_t status; + int32_t val; + + tud_task(); + val = usb_rx_byte(port); + if (val != -1) + return val; + + status = save_and_disable_interrupts(); + + if (uart1_buf.prod == uart1_buf.cons) + val = -1; + else + val = uart1_buf.buf[uart1_buf.cons++]; + + restore_interrupts(status); + + return val; +} + +static void serial1_flush(void) {} + +static const struct upstream_ops serial1_upstream_ops = { + .tx_bytes = serial1_tx_bytes, + .rx_byte = serial1_rx_byte, + .flush = serial1_flush, +}; + const struct upstream_ops *upstream_ops; void upstream_tx_str(int32_t port, const char *str) @@ -238,12 +294,28 @@ void upstream_tx_str(int32_t port, const char *str) } while (*str); } +void set_upstream_ops(bool serial) +{ + if (serial) { + upstream_ops = &serial1_upstream_ops; + } else { + upstream_ops = &usb_upstream_ops; + } + + __dsb(); +} + +bool upstream_is_serial(void) +{ + return upstream_ops == &serial1_upstream_ops; +} + int main(void) { bool success; int port; - upstream_ops = &usb_upstream_ops; + set_upstream_ops(false); success = set_sys_clock_khz(133000, false); @@ -474,8 +474,14 @@ static void help(struct vdm_context *cxt) "^_ ^D Toggle debug\n" "^_ ^M Send empty debug VDM\n" "^_ 1 Serial on Primary USB pins\n" - "^_ 2 Serial on SBU pins\n" - "^_ ? This message\n"); + "^_ 2 Serial on SBU pins\n"); + + if (upstream_is_serial()) + cprintf_cont(cxt, "^_ ^@ Send break\n"); + if (PORT(cxt) == 0 && !vdm_contexts[1].hw) + cprintf_cont(cxt, "^_ ^U Switch upstream port USB/Serial\n"); + cprintf_cont(cxt, "^_ ? This message\n"); + for (int i = 0; i < CONFIG_USB_PD_PORT_COUNT; i++) { struct vdm_context *tmp = &vdm_contexts[i]; @@ -483,9 +489,10 @@ static void help(struct vdm_context *cxt) PORT(tmp), tmp->hw ? "present" : "absent"); if (tmp->hw) - cprintf_cont(cxt, ",cc%d,%s%s", + cprintf_cont(cxt, ",cc%d,%s,%s%s", tmp->cc_line + 1, pinsets[tmp->serial_pin_set], + upstream_is_serial() ? "serial" : "USB", tmp->verbose ? ",debug" : ""); cprintf_cont(cxt, "\n"); } @@ -547,6 +554,9 @@ static bool serial_handler(struct vdm_context *cxt) cxt->verbose = !cxt->verbose; cprintf(cxt, "Debug o%s\n", cxt->verbose ? "n" : "ff"); break; + case 0: /* ^@ */ + tud_cdc_send_break_cb(PORT(cxt), 100); + break; case '\r': /* Enter */ debug_poke(cxt); break; @@ -554,6 +564,17 @@ static bool serial_handler(struct vdm_context *cxt) cxt->serial_pin_set = c - '0'; vdm_pd_reset(cxt); break; + case 0x15: /* ^U */ + /* We can't do that if port 1 exists */ + if (PORT(cxt) != 0 || vdm_contexts[1].hw) + break; + + cprintf(cxt, "Upstream switching to %s\n", + !upstream_is_serial() ? "serial" : "USB"); + set_upstream_ops(!upstream_is_serial()); + cprintf(cxt, "Upstream is %s\n", + upstream_is_serial() ? "serial" : "USB"); + break; case 0x18: /* ^X */ cxt->pending = true; evt_disconnect(cxt); |