aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMarc Zyngier <maz@kernel.org>2023-08-27 10:28:11 +0100
committerMarc Zyngier <maz@kernel.org>2023-08-27 10:32:57 +0100
commit1a4c59587137f6a2ebb32ecf6393110402b04d61 (patch)
treee8d8ab105f6087f2154a4da67b0232e6adff6378
parent0a4652cd6fff2bfdfc223f2a0ef4d6e4d1bdb3ad (diff)
downloadcs-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.h2
-rw-r--r--start.c76
-rw-r--r--vdmtool.c27
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);
diff --git a/start.c b/start.c
index 10c4394..d80acdd 100644
--- a/start.c
+++ b/start.c
@@ -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);
diff --git a/vdmtool.c b/vdmtool.c
index 54b2c26..ddf7ba4 100644
--- a/vdmtool.c
+++ b/vdmtool.c
@@ -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);