laforge has submitted this change. ( 
https://gerrit.osmocom.org/c/osmo-e1-hardware/+/21775 )

Change subject: icE1usb fw: USB control request handling
......................................................................

icE1usb fw: USB control request handling

This introduces a number of vendor-specific control requests for
configuration of the icE1usb from the host software.

Closes: OS#4675
Change-Id: I9d28566ba21a2a78def5e4a0ba07ecbc4a583aa9
---
M firmware/ice40-riscv/icE1usb/e1.c
M firmware/ice40-riscv/icE1usb/e1.h
M firmware/ice40-riscv/icE1usb/fw_app.c
A firmware/ice40-riscv/icE1usb/ice1usb_proto.h
M firmware/ice40-riscv/icE1usb/usb_e1.c
5 files changed, 224 insertions(+), 18 deletions(-)

Approvals:
  Jenkins Builder: Verified
  tnt: Looks good to me, but someone else must approve
  laforge: Looks good to me, approved



diff --git a/firmware/ice40-riscv/icE1usb/e1.c 
b/firmware/ice40-riscv/icE1usb/e1.c
index 1d8fd30..16c8c80 100644
--- a/firmware/ice40-riscv/icE1usb/e1.c
+++ b/firmware/ice40-riscv/icE1usb/e1.c
@@ -238,7 +238,7 @@


 void
-e1_init(bool clk_mode)
+e1_init(uint16_t rx_cr, uint16_t tx_cr)
 {
        /* Global state init */
        memset(&g_e1, 0x00, sizeof(g_e1));
@@ -248,14 +248,11 @@
        e1f_reset(&g_e1.tx.fifo, 128, 128);

        /* Enable Rx */
-       g_e1.rx.cr = E1_RX_CR_MODE_MFA |
-                    E1_RX_CR_ENABLE;
+       g_e1.rx.cr = E1_RX_CR_ENABLE | rx_cr;
        e1_regs->rx.csr = E1_RX_CR_OVFL_CLR | g_e1.rx.cr;

        /* Enable Tx */
-       g_e1.tx.cr = (clk_mode ? E1_TX_CR_TICK_REMOTE : E1_TX_CR_TICK_LOCAL) |
-                    E1_TX_CR_MODE_TS0_CRC_E |
-                    E1_TX_CR_ENABLE;
+       g_e1.tx.cr = E1_TX_CR_ENABLE | tx_cr;
        e1_regs->tx.csr = E1_TX_CR_UNFL_CLR | g_e1.tx.cr;

        /* State */
diff --git a/firmware/ice40-riscv/icE1usb/e1.h 
b/firmware/ice40-riscv/icE1usb/e1.h
index 05ce19a..fcd4284 100644
--- a/firmware/ice40-riscv/icE1usb/e1.h
+++ b/firmware/ice40-riscv/icE1usb/e1.h
@@ -7,7 +7,7 @@

 #pragma once

-void e1_init(bool clk_mode);
+void e1_init(uint16_t rx_cr, uint16_t tx_cr);
 void e1_poll(void);
 void e1_debug_print(bool data);

diff --git a/firmware/ice40-riscv/icE1usb/fw_app.c 
b/firmware/ice40-riscv/icE1usb/fw_app.c
index 62f4b0e..eebc21f 100644
--- a/firmware/ice40-riscv/icE1usb/fw_app.c
+++ b/firmware/ice40-riscv/icE1usb/fw_app.c
@@ -102,7 +102,7 @@
        usb_e1_init();

        /* Start */
-       e1_init(false);         // local tick
+       e1_init(0, 0);
        e1_active = true;
        led_state(true);
        usb_connect();
@@ -138,16 +138,6 @@
                        case 'O':
                                e1_debug_print(true);
                                break;
-                       case 'e':
-                               e1_init(true);
-                               e1_active = true;
-                               led_state(true);
-                               break;
-                       case 'E':
-                               e1_init(false);
-                               e1_active = true;
-                               led_state(true);
-                               break;
                        case 'c':
                                usb_connect();
                                break;
diff --git a/firmware/ice40-riscv/icE1usb/ice1usb_proto.h 
b/firmware/ice40-riscv/icE1usb/ice1usb_proto.h
new file mode 100644
index 0000000..61e12ad
--- /dev/null
+++ b/firmware/ice40-riscv/icE1usb/ice1usb_proto.h
@@ -0,0 +1,77 @@
+/*
+ * ice1usb_proto.h
+ *
+ * Copyright (C) 2020  Harald Welte <[email protected]>
+ * SPDX-License-Identifier: MIT
+ *
+ * Header file describing the USB protocol between the icE1usb firmware and 
the host
+ * software (currently really only osmo-e1d)
+ */
+
+#pragma once
+
+/***********************************************************************
+ * Control Endpoint / Device Requests
+ ***********************************************************************/
+
+/*! returns a bit-mask of optional device capabilities (see enum 
e1usb_dev_capability) */
+#define ICE1USB_DEV_GET_CAPABILITIES   0x01
+#define ICE1USB_DEV_GET_FW_BUILD       0x02
+
+enum e1usb_dev_capability {
+       /*! Does this board have a GPS-DO */
+       ICE1USB_DEV_CAP_GPSDO,
+};
+
+
+/* Interface Requests */
+
+/*! returns a bit-mask of optional device capabilities (see enum 
e1usb_intf_capability) */
+#define ICE1USB_INTF_GET_CAPABILITIES  0x01
+#define ICE1USB_INTF_SET_TX_CFG                0x02    /*!< struct 
ice1usb_tx_config */
+#define ICE1USB_INTF_GET_TX_CFG                0x03    /*!< struct 
ice1usb_tx_config */
+#define ICE1USB_INTF_SET_RX_CFG                0x04    /*!< struct 
ice1usb_rx_config */
+#define ICE1USB_INTF_GET_RX_CFG                0x05    /*!< struct 
ice1usb_rx_config */
+
+//enum e1usb_intf_capability { };
+
+enum ice1usb_tx_mode {
+       ICE1USB_TX_MODE_TRANSP          = 0,
+       ICE1USB_TX_MODE_TS0             = 1,
+       ICE1USB_TX_MODE_TS0_CRC4        = 2,
+       ICE1USB_TX_MODE_TS0_CRC4_E      = 3,
+};
+
+enum ice1usb_tx_timing {
+       ICE1USB_TX_TIME_SRC_LOCAL       = 0,
+       ICE1USB_TX_TIME_SRC_REMOTE      = 1,
+};
+
+enum ice1usb_tx_ext_loopback {
+       ICE1USB_TX_EXT_LOOPBACK_OFF     = 0,
+       ICE1USB_TX_EXT_LOOPBACK_SAME    = 1,
+       ICE1USB_TX_EXT_LOOPBACK_CROSS   = 2,
+};
+
+/* ICE1USB_INTF_{GET,SET}_TX_CFG */
+struct ice1usb_tx_config {
+       uint8_t mode;           /*!< enum ice1usb_tx_mode */
+       uint8_t timing;         /*!< enum ice1usb_tx_timing */
+       uint8_t ext_loopback;   /*!< enum ice1usb_tx_ext_loopback */
+       uint8_t alarm;          /*!< 1 = transmit alarm; 0 = don't */
+} __attribute__((packed));
+
+
+enum ice1usb_rx_mode {
+       /*! transparent, unaligned bitstream */
+       ICE1USB_RX_MODE_TRANSP          = 0,
+       /*! alignment to E1 frame */
+       ICE1USB_RX_MODE_FRAME           = 2,
+       /*! alignment to E1 multiframe */
+       ICE1USB_RX_MODE_MULTIFRAME      = 3,
+};
+
+/* ICE1USB_INTF_{GET,SET}_RX_CFG */
+struct ice1usb_rx_config {
+       uint8_t mode;           /*!< enum ice1usb_rx_mode */
+} __attribute__((packed));
diff --git a/firmware/ice40-riscv/icE1usb/usb_e1.c 
b/firmware/ice40-riscv/icE1usb/usb_e1.c
index e37edc3..0698de5 100644
--- a/firmware/ice40-riscv/icE1usb/usb_e1.c
+++ b/firmware/ice40-riscv/icE1usb/usb_e1.c
@@ -15,13 +15,30 @@
 #include "console.h"
 #include "misc.h"
 #include "e1.h"
+#include "e1_hw.h"
+
+#include "ice1usb_proto.h"

 struct {
        bool running;           /* are we running (transceiving USB data)? */
        int out_bdi;            /* buffer descriptor index for OUT EP */
        int in_bdi;             /* buffer descriptor index for IN EP */
+       struct ice1usb_tx_config tx_cfg;
+       struct ice1usb_rx_config rx_cfg;
 } g_usb_e1;

+/* default configuration at power-up */
+static const struct ice1usb_tx_config tx_cfg_default = {
+       .mode           = ICE1USB_TX_MODE_TS0_CRC4_E,
+       .timing         = ICE1USB_TX_TIME_SRC_LOCAL,
+       .ext_loopback   = ICE1USB_TX_EXT_LOOPBACK_OFF,
+       .alarm          = 0,
+};
+
+static const struct ice1usb_rx_config rx_cfg_default = {
+       .mode           = ICE1USB_RX_MODE_MULTIFRAME,
+};
+

 /* Hack */
 unsigned int e1_rx_need_data(unsigned int usb_addr, unsigned int max_len, 
unsigned int *pos);
@@ -200,6 +217,21 @@
        return USB_FND_SUCCESS;
 }

+static void _perform_tx_config(void)
+{
+       const struct ice1usb_tx_config *cfg = &g_usb_e1.tx_cfg;
+       e1_tx_config(   ((cfg->mode & 3) << 1) |
+                       ((cfg->timing & 1) << 3) |
+                       ((cfg->alarm & 1) << 4) |
+                       ((cfg->ext_loopback & 3) << 5) );
+}
+
+static void _perform_rx_config(void)
+{
+       const struct ice1usb_rx_config *cfg = &g_usb_e1.rx_cfg;
+       e1_rx_config((cfg->mode << 1));
+}
+
 static enum usb_fnd_resp
 _e1_set_intf(const struct usb_intf_desc *base, const struct usb_intf_desc *sel)
 {
@@ -213,6 +245,9 @@
        if (g_usb_e1.running)
                return USB_FND_SUCCESS;

+       _perform_rx_config();
+       _perform_tx_config();
+
        g_usb_e1.running = true;

        /* Configure EP1 OUT / EP2 IN */
@@ -253,15 +288,122 @@
        return USB_FND_SUCCESS;
 }

+static bool
+_set_tx_mode_done(struct usb_xfer *xfer)
+{
+       const struct ice1usb_tx_config *cfg = (const struct ice1usb_tx_config 
*) xfer->data;
+       printf("set_tx_mode %02x%02x%02x%02x\r\n",
+               xfer->data[0], xfer->data[1], xfer->data[2], xfer->data[3]);
+       g_usb_e1.tx_cfg = *cfg;
+       _perform_tx_config();
+       return true;
+}
+
+static bool
+_set_rx_mode_done(struct usb_xfer *xfer)
+{
+       const struct ice1usb_rx_config *cfg = (const struct ice1usb_rx_config 
*) xfer->data;
+       printf("set_rx_mode %02x\r\n", xfer->data[0]);
+       g_usb_e1.rx_cfg = *cfg;
+       _perform_rx_config();
+       return true;
+}
+
+/* per-interface requests */
+static enum usb_fnd_resp
+_e1_ctrl_req_intf(struct usb_ctrl_req *req, struct usb_xfer *xfer)
+{
+       unsigned int i;
+
+       switch (req->bRequest) {
+       case ICE1USB_INTF_GET_CAPABILITIES:
+               /* no optional capabilities yet */
+               xfer->len = 0;
+               break;
+       case ICE1USB_INTF_SET_TX_CFG:
+               if (req->wLength < sizeof(struct ice1usb_tx_config))
+                       return USB_FND_ERROR;
+               xfer->cb_done = _set_tx_mode_done;
+               xfer->cb_ctx = req;
+               xfer->len = sizeof(struct ice1usb_tx_config);
+               break;
+       case ICE1USB_INTF_GET_TX_CFG:
+               if (req->wLength < sizeof(struct ice1usb_tx_config))
+                       return USB_FND_ERROR;
+               memcpy(xfer->data, &g_usb_e1.tx_cfg, sizeof(struct 
ice1usb_tx_config));
+               xfer->len = sizeof(struct ice1usb_tx_config);
+               break;
+       case ICE1USB_INTF_SET_RX_CFG:
+               if (req->wLength < sizeof(struct ice1usb_rx_config))
+                       return USB_FND_ERROR;
+               xfer->cb_done = _set_rx_mode_done;
+               xfer->cb_ctx = req;
+               xfer->len = sizeof(struct ice1usb_rx_config);
+               break;
+       case ICE1USB_INTF_GET_RX_CFG:
+               if (req->wLength < sizeof(struct ice1usb_rx_config))
+                       return USB_FND_ERROR;
+               memcpy(xfer->data, &g_usb_e1.rx_cfg, sizeof(struct 
ice1usb_rx_config));
+               xfer->len = sizeof(struct ice1usb_rx_config);
+               break;
+       default:
+               return USB_FND_ERROR;
+       }
+
+       return USB_FND_SUCCESS;
+}
+
+/* device-global requests */
+static enum usb_fnd_resp
+_e1_ctrl_req_dev(struct usb_ctrl_req *req, struct usb_xfer *xfer)
+{
+       switch (req->bRequest) {
+       case ICE1USB_DEV_GET_CAPABILITIES:
+               xfer->data[0] = (1 << ICE1USB_DEV_CAP_GPSDO);
+               xfer->len = 1;
+               break;
+       default:
+               return USB_FND_ERROR;
+       }
+
+       return USB_FND_SUCCESS;
+}
+
+
+/* USB host issues a control request to us */
+static enum usb_fnd_resp
+_e1_ctrl_req(struct usb_ctrl_req *req, struct usb_xfer *xfer)
+{
+       if (USB_REQ_TYPE(req) != USB_REQ_TYPE_VENDOR)
+               return USB_FND_CONTINUE;
+
+       switch (USB_REQ_RCPT(req)) {
+       case USB_REQ_RCPT_DEV:
+               return _e1_ctrl_req_dev(req, xfer);
+       case USB_REQ_RCPT_INTF:
+               if (req->wIndex != 0)
+                       return USB_FND_ERROR;
+               return _e1_ctrl_req_intf(req, xfer);
+       case USB_REQ_RCPT_EP:
+       case USB_REQ_RCPT_OTHER:
+       default:
+               return USB_FND_ERROR;
+       }
+}
+
+
 static struct usb_fn_drv _e1_drv = {
        .set_conf       = _e1_set_conf,
         .set_intf       = _e1_set_intf,
         .get_intf       = _e1_get_intf,
+       .ctrl_req       = _e1_ctrl_req,
 };

 void
 usb_e1_init(void)
 {
        memset(&g_usb_e1, 0x00, sizeof(g_usb_e1));
+       g_usb_e1.tx_cfg = tx_cfg_default;
+       g_usb_e1.rx_cfg = rx_cfg_default;
        usb_register_function_driver(&_e1_drv);
 }

--
To view, visit https://gerrit.osmocom.org/c/osmo-e1-hardware/+/21775
To unsubscribe, or for help writing mail filters, visit 
https://gerrit.osmocom.org/settings

Gerrit-Project: osmo-e1-hardware
Gerrit-Branch: master
Gerrit-Change-Id: I9d28566ba21a2a78def5e4a0ba07ecbc4a583aa9
Gerrit-Change-Number: 21775
Gerrit-PatchSet: 6
Gerrit-Owner: laforge <[email protected]>
Gerrit-Reviewer: Jenkins Builder
Gerrit-Reviewer: laforge <[email protected]>
Gerrit-Reviewer: tnt <[email protected]>
Gerrit-MessageType: merged

Reply via email to