icE1usb fw: Add Notify PPS on Carrier Detect option
This is disabled by default because turns out the kernel doesn't
actually support PPS on CD for USB-CDC devices :(
And this also increase the interrupt traffic ...
Signed-off-by: Sylvain Munaut <tnt@246tNt.com>
Change-Id: Ie5d163434323a23912228003add9870fafefedf9
diff --git a/firmware/ice40-riscv/icE1usb/usb_desc_app.c b/firmware/ice40-riscv/icE1usb/usb_desc_app.c
index 25472e0..7dfc304 100644
--- a/firmware/ice40-riscv/icE1usb/usb_desc_app.c
+++ b/firmware/ice40-riscv/icE1usb/usb_desc_app.c
@@ -250,7 +250,11 @@
.bmAttributes = 0x03,
/* Longest notif is SERIAL_STATE with 2 data bytes */
.wMaxPacketSize = sizeof(struct usb_ctrl_req) + 2,
+#ifdef GPS_PPS_ON_CD
+ .bInterval = 1,
+#else
.bInterval = 0x40,
+#endif
},
.intf_data = {
.bLength = sizeof(struct usb_intf_desc),
diff --git a/firmware/ice40-riscv/icE1usb/usb_gps.c b/firmware/ice40-riscv/icE1usb/usb_gps.c
index 1c10033..7ca89fd 100644
--- a/firmware/ice40-riscv/icE1usb/usb_gps.c
+++ b/firmware/ice40-riscv/icE1usb/usb_gps.c
@@ -17,6 +17,7 @@
#include <no2usb/usb_cdc_proto.h>
#include "console.h"
+#include "misc.h"
#include "usb_desc_ids.h"
@@ -34,9 +35,23 @@
unsigned int rd;
char data[BUF_SIZE] __attribute__((aligned(4)));
} buf;
+
+#ifdef GPS_PPS_ON_CD
+ /* PPS tracking */
+ struct {
+ uint32_t last;
+ bool set;
+ } pps;
+#endif
} g_usb_gps;
+struct usb_cdc_notif_serial_state {
+ struct usb_ctrl_req hdr;
+ uint16_t bits;
+};
+
+
static void
_usb_gps_set_active(bool active)
{
@@ -120,6 +135,53 @@
else
ep_regs->bd[0].csr = 0;
}
+
+#ifdef GPS_PPS_ON_CD
+ /* IN EP CTL: Send PPS pulse */
+ ep_regs = &usb_ep_regs[USB_EP_GPS_CDC_CTL & 0x1f].in;
+
+ if ((ep_regs->bd[0].csr & USB_BD_STATE_MSK) != USB_BD_STATE_RDY_DATA)
+ {
+ /* Default request */
+ struct usb_cdc_notif_serial_state notif = {
+ .hdr = {
+ .bmRequestType = USB_REQ_READ | USB_REQ_TYPE_CLASS | USB_REQ_RCPT_INTF,
+ .bRequest = USB_NOTIF_CDC_SERIAL_STATE,
+ .wValue = 0,
+ .wIndex = USB_INTF_GPS_CDC_CTL,
+ .wLength = 2
+ },
+ .bits = 0x00
+ };
+
+ /* Check if PPS occurred */
+ uint32_t pps_now = time_pps_read();
+
+ if (pps_now != g_usb_gps.pps.last)
+ {
+ /* Update last */
+ g_usb_gps.pps.last = pps_now;
+
+ /* Queue CD Set */
+ notif.bits = 1;
+ usb_data_write(ep_regs->bd[0].ptr, ¬if, 12);
+ ep_regs->bd[0].csr = USB_BD_STATE_RDY_DATA | USB_BD_LEN(10);
+
+ /* Need to clear in the future */
+ g_usb_gps.pps.set = true;
+ }
+ else if (g_usb_gps.pps.set)
+ {
+ /* Queue CD Clear */
+ notif.bits = 0;
+ usb_data_write(ep_regs->bd[0].ptr, ¬if, 12);
+ ep_regs->bd[0].csr = USB_BD_STATE_RDY_DATA | USB_BD_LEN(10);
+
+ /* Cleared */
+ g_usb_gps.pps.set = false;
+ }
+ }
+#endif
}