blob: 75811c2416803cc346550127754ac4a56ed728c8 [file] [log] [blame]
Sylvain Munautbc9f5c42020-09-14 10:22:29 +02001/*
2 * usb_e1.c
3 *
4 * Copyright (C) 2019-2020 Sylvain Munaut <tnt@246tNt.com>
5 * SPDX-License-Identifier: GPL-3.0-or-later
6 */
7
8#include <stdint.h>
9#include <stdbool.h>
10#include <string.h>
11
12#include <no2usb/usb_hw.h>
13#include <no2usb/usb_priv.h>
14
15#include "console.h"
Harald Welte2df1f802020-12-14 17:46:53 +010016#include "e1.h"
Sylvain Munautff44f142022-01-03 20:34:23 +010017#include "misc.h"
18#include "usb_desc_ids.h"
Harald Welte9469e042020-12-15 23:09:40 +010019
20#include "ice1usb_proto.h"
Sylvain Munautbc9f5c42020-09-14 10:22:29 +020021
22struct {
Harald Welte30fc5602020-12-14 15:56:28 +010023 bool running; /* are we running (transceiving USB data)? */
24 int out_bdi; /* buffer descriptor index for OUT EP */
25 int in_bdi; /* buffer descriptor index for IN EP */
Harald Welte9469e042020-12-15 23:09:40 +010026 struct ice1usb_tx_config tx_cfg;
27 struct ice1usb_rx_config rx_cfg;
Harald Welte805f2cf2020-12-14 17:31:03 +010028 struct e1_error_count last_err;
Sylvain Munautbc9f5c42020-09-14 10:22:29 +020029} g_usb_e1;
30
Harald Welte9469e042020-12-15 23:09:40 +010031/* default configuration at power-up */
32static const struct ice1usb_tx_config tx_cfg_default = {
33 .mode = ICE1USB_TX_MODE_TS0_CRC4_E,
34 .timing = ICE1USB_TX_TIME_SRC_LOCAL,
35 .ext_loopback = ICE1USB_TX_EXT_LOOPBACK_OFF,
36 .alarm = 0,
37};
38
39static const struct ice1usb_rx_config rx_cfg_default = {
40 .mode = ICE1USB_RX_MODE_MULTIFRAME,
41};
42
Sylvain Munautbc9f5c42020-09-14 10:22:29 +020043
Sylvain Munautff44f142022-01-03 20:34:23 +010044static volatile struct usb_ep *
45_get_ep_regs(uint8_t ep)
46{
47 return (ep & 0x80) ? &usb_ep_regs[ep & 0x1f].in : &usb_ep_regs[ep & 0x1f].out;
48}
49
Sylvain Munautbc9f5c42020-09-14 10:22:29 +020050static void
51_usb_fill_feedback_ep(void)
52{
53 static uint16_t ticks_prev = 0;
54 uint16_t ticks;
55 uint32_t val = 8192;
56 unsigned int level;
Sylvain Munautff44f142022-01-03 20:34:23 +010057 volatile struct usb_ep *ep_regs;
Sylvain Munautbc9f5c42020-09-14 10:22:29 +020058
Harald Welte2b7dadf2020-12-14 15:56:15 +010059 /* Compute real E1 tick count (with safety against bad values) */
Sylvain Munaut436b7752022-01-03 22:09:54 +010060 ticks = e1_tick_read(0);
Sylvain Munautbc9f5c42020-09-14 10:22:29 +020061 val = (ticks - ticks_prev) & 0xffff;
62 ticks_prev = ticks;
63 if ((val < 7168) | (val > 9216))
64 val = 8192;
65
66 /* Bias depending on TX fifo level */
Sylvain Munaut3da51512022-01-03 22:12:59 +010067 level = e1_tx_level(0);
Sylvain Munautbc9f5c42020-09-14 10:22:29 +020068 if (level < (3 * 16))
69 val += 256;
70 else if (level > (8 * 16))
71 val -= 256;
72
73 /* Prepare buffer */
Sylvain Munautff44f142022-01-03 20:34:23 +010074 ep_regs = _get_ep_regs(USB_EP_E1_FB(0));
75 usb_data_write(ep_regs->bd[0].ptr, &val, 4);
76 ep_regs->bd[0].csr = USB_BD_STATE_RDY_DATA | USB_BD_LEN(3);
Sylvain Munautbc9f5c42020-09-14 10:22:29 +020077}
78
79
80void
81usb_e1_run(void)
82{
Sylvain Munautff44f142022-01-03 20:34:23 +010083 volatile struct usb_ep *ep_regs;
Sylvain Munautbc9f5c42020-09-14 10:22:29 +020084 int bdi;
85
86 if (!g_usb_e1.running)
87 return;
88
Sylvain Munautff44f142022-01-03 20:34:23 +010089 /* Interrupt endpoint */
90 ep_regs = _get_ep_regs(USB_EP_E1_INT(0));
91
92 if ((ep_regs->bd[0].csr & USB_BD_STATE_MSK) != USB_BD_STATE_RDY_DATA) {
Sylvain Munaut3da51512022-01-03 22:12:59 +010093 const struct e1_error_count *cur_err = e1_get_error_count(0);
Harald Welte805f2cf2020-12-14 17:31:03 +010094 if (memcmp(cur_err, &g_usb_e1.last_err, sizeof(*cur_err))) {
95 struct ice1usb_irq errmsg = {
96 .type = ICE1USB_IRQ_T_ERRCNT,
97 .u = {
98 .errors = {
99 .crc = cur_err->crc,
100 .align = cur_err->align,
101 .ovfl = cur_err->ovfl,
102 .unfl = cur_err->unfl,
103 .flags = cur_err->flags,
104 }
105 }
106 };
107 printf("E");
Sylvain Munautff44f142022-01-03 20:34:23 +0100108 usb_data_write(ep_regs->bd[0].ptr, &errmsg, sizeof(errmsg));
109 ep_regs->bd[0].csr = USB_BD_STATE_RDY_DATA | USB_BD_LEN(sizeof(errmsg));
Harald Welte805f2cf2020-12-14 17:31:03 +0100110 g_usb_e1.last_err = *cur_err;
111 }
112 }
113
Sylvain Munautff44f142022-01-03 20:34:23 +0100114 /* Data IN endpoint */
115 ep_regs = _get_ep_regs(USB_EP_E1_IN(0));
Sylvain Munautbc9f5c42020-09-14 10:22:29 +0200116 bdi = g_usb_e1.in_bdi;
117
Sylvain Munautff44f142022-01-03 20:34:23 +0100118 while ((ep_regs->bd[bdi].csr & USB_BD_STATE_MSK) != USB_BD_STATE_RDY_DATA)
Sylvain Munautbc9f5c42020-09-14 10:22:29 +0200119 {
Sylvain Munautff44f142022-01-03 20:34:23 +0100120 uint32_t ptr = ep_regs->bd[bdi].ptr;
Sylvain Munautbc9f5c42020-09-14 10:22:29 +0200121 uint32_t hdr;
Harald Welte2df1f802020-12-14 17:46:53 +0100122 unsigned int pos;
Sylvain Munautbc9f5c42020-09-14 10:22:29 +0200123
124 /* Error check */
Sylvain Munautff44f142022-01-03 20:34:23 +0100125 if ((ep_regs->bd[bdi].csr & USB_BD_STATE_MSK) == USB_BD_STATE_DONE_ERR)
126 puts("Err EP IN\n");
Sylvain Munautbc9f5c42020-09-14 10:22:29 +0200127
128 /* Get some data from E1 */
Sylvain Munaut3da51512022-01-03 22:12:59 +0100129 int n = e1_rx_level(0);
Sylvain Munautbc9f5c42020-09-14 10:22:29 +0200130
Sylvain Munaut1d987092022-01-05 21:04:09 +0100131 if (n > 32)
132 n = 9;
Sylvain Munautbc9f5c42020-09-14 10:22:29 +0200133 else if (n > 8)
134 n = 8;
135 else if (!n)
136 break;
137
Sylvain Munaut3da51512022-01-03 22:12:59 +0100138 n = e1_rx_need_data(0, (ptr >> 2) + 1, n, &pos);
Sylvain Munautbc9f5c42020-09-14 10:22:29 +0200139
Harald Welte2df1f802020-12-14 17:46:53 +0100140 /* Write header: currently version and pos (mfr/fr number) */
141 hdr = (0 << 28) | (pos & 0xff);
Sylvain Munautbc9f5c42020-09-14 10:22:29 +0200142 usb_data_write(ptr, &hdr, 4);
143
144 /* Resubmit */
Sylvain Munautff44f142022-01-03 20:34:23 +0100145 ep_regs->bd[bdi].csr = USB_BD_STATE_RDY_DATA | USB_BD_LEN((n * 32) + 4);
Sylvain Munautbc9f5c42020-09-14 10:22:29 +0200146
147 /* Next BDI */
148 bdi ^= 1;
149 g_usb_e1.in_bdi = bdi;
150 }
151
Sylvain Munautff44f142022-01-03 20:34:23 +0100152 /* Data OUT endpoint */
153 ep_regs = _get_ep_regs(USB_EP_E1_OUT(0));
Sylvain Munautbc9f5c42020-09-14 10:22:29 +0200154 bdi = g_usb_e1.out_bdi;
155
Sylvain Munautff44f142022-01-03 20:34:23 +0100156 while ((ep_regs->bd[bdi].csr & USB_BD_STATE_MSK) != USB_BD_STATE_RDY_DATA)
Sylvain Munautbc9f5c42020-09-14 10:22:29 +0200157 {
Sylvain Munautff44f142022-01-03 20:34:23 +0100158 uint32_t ptr = ep_regs->bd[bdi].ptr;
159 uint32_t csr = ep_regs->bd[bdi].csr;
Sylvain Munautbc9f5c42020-09-14 10:22:29 +0200160 uint32_t hdr;
161
162 /* Error check */
163 if ((csr & USB_BD_STATE_MSK) == USB_BD_STATE_DONE_ERR) {
Sylvain Munautff44f142022-01-03 20:34:23 +0100164 puts("Err EP OUT\n");
Sylvain Munautbc9f5c42020-09-14 10:22:29 +0200165 goto refill;
166 }
167
168 /* Grab header */
169 usb_data_read(&hdr, ptr, 4);
170
171 /* Empty data into the FIFO */
Sylvain Munautd108dfb2022-01-03 21:11:05 +0100172 int n = ((int)(csr & USB_BD_LEN_MSK) - 6) / 32;
173 if (n > 0)
Sylvain Munaut3da51512022-01-03 22:12:59 +0100174 e1_tx_feed_data(0, (ptr >> 2) + 1, n);
Sylvain Munautbc9f5c42020-09-14 10:22:29 +0200175
176refill:
177 /* Refill it */
Sylvain Munaut1d987092022-01-05 21:04:09 +0100178 ep_regs->bd[bdi].csr = USB_BD_STATE_RDY_DATA | USB_BD_LEN(292);
Sylvain Munautbc9f5c42020-09-14 10:22:29 +0200179
180 /* Next BDI */
181 bdi ^= 1;
182 g_usb_e1.out_bdi = bdi;
183
184 static int x = 0;
185 if ((x++ & 0xff) == 0xff)
186 puts(".");
187 }
188
Sylvain Munautff44f142022-01-03 20:34:23 +0100189 /* Feedback endpoint */
190 ep_regs = _get_ep_regs(USB_EP_E1_FB(0));
191
192 if ((ep_regs->bd[0].csr & USB_BD_STATE_MSK) != USB_BD_STATE_RDY_DATA)
Sylvain Munautbc9f5c42020-09-14 10:22:29 +0200193 {
194 _usb_fill_feedback_ep();
195 }
196}
197
Harald Weltec8271852020-12-14 13:48:09 +0100198static enum usb_fnd_resp
Sylvain Munautbc9f5c42020-09-14 10:22:29 +0200199_e1_set_conf(const struct usb_conf_desc *conf)
200{
201 const struct usb_intf_desc *intf;
202
203 printf("e1 set_conf %08x\n", conf);
204 if (!conf)
205 return USB_FND_SUCCESS;
206
Sylvain Munautff44f142022-01-03 20:34:23 +0100207 intf = usb_desc_find_intf(conf, USB_INTF_E1(0), 0, NULL);
Sylvain Munautbc9f5c42020-09-14 10:22:29 +0200208 if (!intf)
209 return USB_FND_ERROR;
210
211 printf("e1 set_conf %08x\n", intf);
212
Sylvain Munautff44f142022-01-03 20:34:23 +0100213 usb_ep_boot(intf, USB_EP_E1_IN(0), true);
214 usb_ep_boot(intf, USB_EP_E1_OUT(0), true);
215 usb_ep_boot(intf, USB_EP_E1_FB(0), false);
216 usb_ep_boot(intf, USB_EP_E1_INT(0), false);
Sylvain Munautbc9f5c42020-09-14 10:22:29 +0200217
218 return USB_FND_SUCCESS;
219}
220
Harald Welte9469e042020-12-15 23:09:40 +0100221static void _perform_tx_config(void)
222{
223 const struct ice1usb_tx_config *cfg = &g_usb_e1.tx_cfg;
Sylvain Munaut3da51512022-01-03 22:12:59 +0100224 e1_tx_config(0,
225 ((cfg->mode & 3) << 1) |
226 ((cfg->timing & 1) << 3) |
227 ((cfg->alarm & 1) << 4) |
228 ((cfg->ext_loopback & 3) << 5)
229 );
Harald Welte9469e042020-12-15 23:09:40 +0100230}
231
232static void _perform_rx_config(void)
233{
234 const struct ice1usb_rx_config *cfg = &g_usb_e1.rx_cfg;
Sylvain Munaut3da51512022-01-03 22:12:59 +0100235 e1_rx_config(0,
236 (cfg->mode << 1)
237 );
Harald Welte9469e042020-12-15 23:09:40 +0100238}
239
Harald Weltec8271852020-12-14 13:48:09 +0100240static enum usb_fnd_resp
Sylvain Munautbc9f5c42020-09-14 10:22:29 +0200241_e1_set_intf(const struct usb_intf_desc *base, const struct usb_intf_desc *sel)
242{
Sylvain Munautff44f142022-01-03 20:34:23 +0100243 volatile struct usb_ep *ep_regs;
244
Sylvain Munaut96744362022-01-03 17:03:26 +0100245 /* Validity checks */
Sylvain Munautff44f142022-01-03 20:34:23 +0100246 if ((base->bInterfaceClass != 0xff) || (base->bInterfaceSubClass != 0xe1))
Sylvain Munautbc9f5c42020-09-14 10:22:29 +0200247 return USB_FND_CONTINUE;
248
Sylvain Munaut96744362022-01-03 17:03:26 +0100249 if (sel->bAlternateSetting > 1)
250 return USB_FND_ERROR;
Sylvain Munautbc9f5c42020-09-14 10:22:29 +0200251
Sylvain Munaut96744362022-01-03 17:03:26 +0100252 /* Don't do anything if no change */
253 if (g_usb_e1.running == (sel->bAlternateSetting != 0))
254 return USB_FND_SUCCESS;
255
256 g_usb_e1.running = (sel->bAlternateSetting != 0);
257
258 /* Reconfigure the endpoints */
Sylvain Munautff44f142022-01-03 20:34:23 +0100259 usb_ep_reconf(sel, USB_EP_E1_IN(0));
260 usb_ep_reconf(sel, USB_EP_E1_OUT(0));
261 usb_ep_reconf(sel, USB_EP_E1_FB(0));
262 usb_ep_reconf(sel, USB_EP_E1_INT(0));
Sylvain Munaut96744362022-01-03 17:03:26 +0100263
264 /* Update E1 and USB state */
265 switch (g_usb_e1.running) {
266 case false:
267 /* Disable E1 rx/tx */
Sylvain Munaut3da51512022-01-03 22:12:59 +0100268 e1_init(0, 0, 0);
Harald Weltee6b0fe82020-12-17 22:22:05 +0100269 break;
Sylvain Munautbc9f5c42020-09-14 10:22:29 +0200270
Sylvain Munaut96744362022-01-03 17:03:26 +0100271 case true:
272 /* Reset and Re-Enable E1 */
Sylvain Munaut3da51512022-01-03 22:12:59 +0100273 e1_init(0, 0, 0);
Harald Weltee6b0fe82020-12-17 22:22:05 +0100274 _perform_rx_config();
275 _perform_tx_config();
Sylvain Munautbc9f5c42020-09-14 10:22:29 +0200276
Sylvain Munaut96744362022-01-03 17:03:26 +0100277 /* Reset BDI */
Harald Weltee6b0fe82020-12-17 22:22:05 +0100278 g_usb_e1.in_bdi = 0;
Sylvain Munaut96744362022-01-03 17:03:26 +0100279 g_usb_e1.out_bdi = 0;
Harald Weltee6b0fe82020-12-17 22:22:05 +0100280
Sylvain Munautff44f142022-01-03 20:34:23 +0100281 /* EP OUT: Queue two buffers */
282 ep_regs = _get_ep_regs(USB_EP_E1_FB(0));
Sylvain Munaut1d987092022-01-05 21:04:09 +0100283 ep_regs->bd[0].csr = USB_BD_STATE_RDY_DATA | USB_BD_LEN(292);
284 ep_regs->bd[1].csr = USB_BD_STATE_RDY_DATA | USB_BD_LEN(292);
Harald Weltee6b0fe82020-12-17 22:22:05 +0100285
Sylvain Munautff44f142022-01-03 20:34:23 +0100286 /* EP Feedback: Pre-fill */
Harald Weltee6b0fe82020-12-17 22:22:05 +0100287 _usb_fill_feedback_ep();
288
Harald Weltee6b0fe82020-12-17 22:22:05 +0100289 break;
Harald Weltee6b0fe82020-12-17 22:22:05 +0100290 }
Harald Welte805f2cf2020-12-14 17:31:03 +0100291
Sylvain Munautbc9f5c42020-09-14 10:22:29 +0200292 return USB_FND_SUCCESS;
293}
294
Harald Weltec8271852020-12-14 13:48:09 +0100295static enum usb_fnd_resp
Sylvain Munautbc9f5c42020-09-14 10:22:29 +0200296_e1_get_intf(const struct usb_intf_desc *base, uint8_t *alt)
297{
Sylvain Munautff44f142022-01-03 20:34:23 +0100298 if ((base->bInterfaceClass != 0xff) || (base->bInterfaceSubClass != 0xe1))
Sylvain Munautbc9f5c42020-09-14 10:22:29 +0200299 return USB_FND_CONTINUE;
300
301 *alt = g_usb_e1.running ? 1 : 0;
302
303 return USB_FND_SUCCESS;
304}
305
Harald Welte9469e042020-12-15 23:09:40 +0100306static bool
307_set_tx_mode_done(struct usb_xfer *xfer)
308{
309 const struct ice1usb_tx_config *cfg = (const struct ice1usb_tx_config *) xfer->data;
310 printf("set_tx_mode %02x%02x%02x%02x\r\n",
311 xfer->data[0], xfer->data[1], xfer->data[2], xfer->data[3]);
312 g_usb_e1.tx_cfg = *cfg;
313 _perform_tx_config();
314 return true;
315}
316
317static bool
318_set_rx_mode_done(struct usb_xfer *xfer)
319{
320 const struct ice1usb_rx_config *cfg = (const struct ice1usb_rx_config *) xfer->data;
321 printf("set_rx_mode %02x\r\n", xfer->data[0]);
322 g_usb_e1.rx_cfg = *cfg;
323 _perform_rx_config();
324 return true;
325}
326
327/* per-interface requests */
328static enum usb_fnd_resp
329_e1_ctrl_req_intf(struct usb_ctrl_req *req, struct usb_xfer *xfer)
330{
331 unsigned int i;
332
333 switch (req->bRequest) {
334 case ICE1USB_INTF_GET_CAPABILITIES:
335 /* no optional capabilities yet */
336 xfer->len = 0;
337 break;
338 case ICE1USB_INTF_SET_TX_CFG:
339 if (req->wLength < sizeof(struct ice1usb_tx_config))
340 return USB_FND_ERROR;
341 xfer->cb_done = _set_tx_mode_done;
342 xfer->cb_ctx = req;
343 xfer->len = sizeof(struct ice1usb_tx_config);
344 break;
345 case ICE1USB_INTF_GET_TX_CFG:
346 if (req->wLength < sizeof(struct ice1usb_tx_config))
347 return USB_FND_ERROR;
348 memcpy(xfer->data, &g_usb_e1.tx_cfg, sizeof(struct ice1usb_tx_config));
349 xfer->len = sizeof(struct ice1usb_tx_config);
350 break;
351 case ICE1USB_INTF_SET_RX_CFG:
352 if (req->wLength < sizeof(struct ice1usb_rx_config))
353 return USB_FND_ERROR;
354 xfer->cb_done = _set_rx_mode_done;
355 xfer->cb_ctx = req;
356 xfer->len = sizeof(struct ice1usb_rx_config);
357 break;
358 case ICE1USB_INTF_GET_RX_CFG:
359 if (req->wLength < sizeof(struct ice1usb_rx_config))
360 return USB_FND_ERROR;
361 memcpy(xfer->data, &g_usb_e1.rx_cfg, sizeof(struct ice1usb_rx_config));
362 xfer->len = sizeof(struct ice1usb_rx_config);
363 break;
364 default:
365 return USB_FND_ERROR;
366 }
367
368 return USB_FND_SUCCESS;
369}
370
371/* device-global requests */
372static enum usb_fnd_resp
373_e1_ctrl_req_dev(struct usb_ctrl_req *req, struct usb_xfer *xfer)
374{
375 switch (req->bRequest) {
376 case ICE1USB_DEV_GET_CAPABILITIES:
377 xfer->data[0] = (1 << ICE1USB_DEV_CAP_GPSDO);
378 xfer->len = 1;
379 break;
380 default:
381 return USB_FND_ERROR;
382 }
383
384 return USB_FND_SUCCESS;
385}
386
387
388/* USB host issues a control request to us */
389static enum usb_fnd_resp
390_e1_ctrl_req(struct usb_ctrl_req *req, struct usb_xfer *xfer)
391{
392 if (USB_REQ_TYPE(req) != USB_REQ_TYPE_VENDOR)
393 return USB_FND_CONTINUE;
394
395 switch (USB_REQ_RCPT(req)) {
396 case USB_REQ_RCPT_DEV:
397 return _e1_ctrl_req_dev(req, xfer);
398 case USB_REQ_RCPT_INTF:
Sylvain Munautff44f142022-01-03 20:34:23 +0100399 if (req->wIndex != USB_INTF_E1(0))
Sylvain Munaut0f40ee02022-01-03 20:33:08 +0100400 return USB_FND_CONTINUE;
Harald Welte9469e042020-12-15 23:09:40 +0100401 return _e1_ctrl_req_intf(req, xfer);
402 case USB_REQ_RCPT_EP:
403 case USB_REQ_RCPT_OTHER:
404 default:
405 return USB_FND_ERROR;
406 }
407}
408
409
Sylvain Munautbc9f5c42020-09-14 10:22:29 +0200410static struct usb_fn_drv _e1_drv = {
411 .set_conf = _e1_set_conf,
412 .set_intf = _e1_set_intf,
413 .get_intf = _e1_get_intf,
Harald Welte9469e042020-12-15 23:09:40 +0100414 .ctrl_req = _e1_ctrl_req,
Sylvain Munautbc9f5c42020-09-14 10:22:29 +0200415};
416
417void
418usb_e1_init(void)
419{
420 memset(&g_usb_e1, 0x00, sizeof(g_usb_e1));
Harald Welte9469e042020-12-15 23:09:40 +0100421 g_usb_e1.tx_cfg = tx_cfg_default;
422 g_usb_e1.rx_cfg = rx_cfg_default;
Sylvain Munautbc9f5c42020-09-14 10:22:29 +0200423 usb_register_function_driver(&_e1_drv);
424}