blob: 8e78ffabd2479ef2d9c603aa1c858740916df3d4 [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
131 if (n > 64)
132 n = 12;
133 else if (n > 32)
134 n = 10;
135 else if (n > 8)
136 n = 8;
137 else if (!n)
138 break;
139
Sylvain Munaut3da51512022-01-03 22:12:59 +0100140 n = e1_rx_need_data(0, (ptr >> 2) + 1, n, &pos);
Sylvain Munautbc9f5c42020-09-14 10:22:29 +0200141
Harald Welte2df1f802020-12-14 17:46:53 +0100142 /* Write header: currently version and pos (mfr/fr number) */
143 hdr = (0 << 28) | (pos & 0xff);
Sylvain Munautbc9f5c42020-09-14 10:22:29 +0200144 usb_data_write(ptr, &hdr, 4);
145
146 /* Resubmit */
Sylvain Munautff44f142022-01-03 20:34:23 +0100147 ep_regs->bd[bdi].csr = USB_BD_STATE_RDY_DATA | USB_BD_LEN((n * 32) + 4);
Sylvain Munautbc9f5c42020-09-14 10:22:29 +0200148
149 /* Next BDI */
150 bdi ^= 1;
151 g_usb_e1.in_bdi = bdi;
152 }
153
Sylvain Munautff44f142022-01-03 20:34:23 +0100154 /* Data OUT endpoint */
155 ep_regs = _get_ep_regs(USB_EP_E1_OUT(0));
Sylvain Munautbc9f5c42020-09-14 10:22:29 +0200156 bdi = g_usb_e1.out_bdi;
157
Sylvain Munautff44f142022-01-03 20:34:23 +0100158 while ((ep_regs->bd[bdi].csr & USB_BD_STATE_MSK) != USB_BD_STATE_RDY_DATA)
Sylvain Munautbc9f5c42020-09-14 10:22:29 +0200159 {
Sylvain Munautff44f142022-01-03 20:34:23 +0100160 uint32_t ptr = ep_regs->bd[bdi].ptr;
161 uint32_t csr = ep_regs->bd[bdi].csr;
Sylvain Munautbc9f5c42020-09-14 10:22:29 +0200162 uint32_t hdr;
163
164 /* Error check */
165 if ((csr & USB_BD_STATE_MSK) == USB_BD_STATE_DONE_ERR) {
Sylvain Munautff44f142022-01-03 20:34:23 +0100166 puts("Err EP OUT\n");
Sylvain Munautbc9f5c42020-09-14 10:22:29 +0200167 goto refill;
168 }
169
170 /* Grab header */
171 usb_data_read(&hdr, ptr, 4);
172
173 /* Empty data into the FIFO */
Sylvain Munautd108dfb2022-01-03 21:11:05 +0100174 int n = ((int)(csr & USB_BD_LEN_MSK) - 6) / 32;
175 if (n > 0)
Sylvain Munaut3da51512022-01-03 22:12:59 +0100176 e1_tx_feed_data(0, (ptr >> 2) + 1, n);
Sylvain Munautbc9f5c42020-09-14 10:22:29 +0200177
178refill:
179 /* Refill it */
Sylvain Munautff44f142022-01-03 20:34:23 +0100180 ep_regs->bd[bdi].csr = USB_BD_STATE_RDY_DATA | USB_BD_LEN(388);
Sylvain Munautbc9f5c42020-09-14 10:22:29 +0200181
182 /* Next BDI */
183 bdi ^= 1;
184 g_usb_e1.out_bdi = bdi;
185
186 static int x = 0;
187 if ((x++ & 0xff) == 0xff)
188 puts(".");
189 }
190
Sylvain Munautff44f142022-01-03 20:34:23 +0100191 /* Feedback endpoint */
192 ep_regs = _get_ep_regs(USB_EP_E1_FB(0));
193
194 if ((ep_regs->bd[0].csr & USB_BD_STATE_MSK) != USB_BD_STATE_RDY_DATA)
Sylvain Munautbc9f5c42020-09-14 10:22:29 +0200195 {
196 _usb_fill_feedback_ep();
197 }
198}
199
Harald Weltec8271852020-12-14 13:48:09 +0100200static enum usb_fnd_resp
Sylvain Munautbc9f5c42020-09-14 10:22:29 +0200201_e1_set_conf(const struct usb_conf_desc *conf)
202{
203 const struct usb_intf_desc *intf;
204
205 printf("e1 set_conf %08x\n", conf);
206 if (!conf)
207 return USB_FND_SUCCESS;
208
Sylvain Munautff44f142022-01-03 20:34:23 +0100209 intf = usb_desc_find_intf(conf, USB_INTF_E1(0), 0, NULL);
Sylvain Munautbc9f5c42020-09-14 10:22:29 +0200210 if (!intf)
211 return USB_FND_ERROR;
212
213 printf("e1 set_conf %08x\n", intf);
214
Sylvain Munautff44f142022-01-03 20:34:23 +0100215 usb_ep_boot(intf, USB_EP_E1_IN(0), true);
216 usb_ep_boot(intf, USB_EP_E1_OUT(0), true);
217 usb_ep_boot(intf, USB_EP_E1_FB(0), false);
218 usb_ep_boot(intf, USB_EP_E1_INT(0), false);
Sylvain Munautbc9f5c42020-09-14 10:22:29 +0200219
220 return USB_FND_SUCCESS;
221}
222
Harald Welte9469e042020-12-15 23:09:40 +0100223static void _perform_tx_config(void)
224{
225 const struct ice1usb_tx_config *cfg = &g_usb_e1.tx_cfg;
Sylvain Munaut3da51512022-01-03 22:12:59 +0100226 e1_tx_config(0,
227 ((cfg->mode & 3) << 1) |
228 ((cfg->timing & 1) << 3) |
229 ((cfg->alarm & 1) << 4) |
230 ((cfg->ext_loopback & 3) << 5)
231 );
Harald Welte9469e042020-12-15 23:09:40 +0100232}
233
234static void _perform_rx_config(void)
235{
236 const struct ice1usb_rx_config *cfg = &g_usb_e1.rx_cfg;
Sylvain Munaut3da51512022-01-03 22:12:59 +0100237 e1_rx_config(0,
238 (cfg->mode << 1)
239 );
Harald Welte9469e042020-12-15 23:09:40 +0100240}
241
Harald Weltec8271852020-12-14 13:48:09 +0100242static enum usb_fnd_resp
Sylvain Munautbc9f5c42020-09-14 10:22:29 +0200243_e1_set_intf(const struct usb_intf_desc *base, const struct usb_intf_desc *sel)
244{
Sylvain Munautff44f142022-01-03 20:34:23 +0100245 volatile struct usb_ep *ep_regs;
246
Sylvain Munaut96744362022-01-03 17:03:26 +0100247 /* Validity checks */
Sylvain Munautff44f142022-01-03 20:34:23 +0100248 if ((base->bInterfaceClass != 0xff) || (base->bInterfaceSubClass != 0xe1))
Sylvain Munautbc9f5c42020-09-14 10:22:29 +0200249 return USB_FND_CONTINUE;
250
Sylvain Munaut96744362022-01-03 17:03:26 +0100251 if (sel->bAlternateSetting > 1)
252 return USB_FND_ERROR;
Sylvain Munautbc9f5c42020-09-14 10:22:29 +0200253
Sylvain Munaut96744362022-01-03 17:03:26 +0100254 /* Don't do anything if no change */
255 if (g_usb_e1.running == (sel->bAlternateSetting != 0))
256 return USB_FND_SUCCESS;
257
258 g_usb_e1.running = (sel->bAlternateSetting != 0);
259
260 /* Reconfigure the endpoints */
Sylvain Munautff44f142022-01-03 20:34:23 +0100261 usb_ep_reconf(sel, USB_EP_E1_IN(0));
262 usb_ep_reconf(sel, USB_EP_E1_OUT(0));
263 usb_ep_reconf(sel, USB_EP_E1_FB(0));
264 usb_ep_reconf(sel, USB_EP_E1_INT(0));
Sylvain Munaut96744362022-01-03 17:03:26 +0100265
266 /* Update E1 and USB state */
267 switch (g_usb_e1.running) {
268 case false:
269 /* Disable E1 rx/tx */
Sylvain Munaut3da51512022-01-03 22:12:59 +0100270 e1_init(0, 0, 0);
Harald Weltee6b0fe82020-12-17 22:22:05 +0100271 break;
Sylvain Munautbc9f5c42020-09-14 10:22:29 +0200272
Sylvain Munaut96744362022-01-03 17:03:26 +0100273 case true:
274 /* Reset and Re-Enable E1 */
Sylvain Munaut3da51512022-01-03 22:12:59 +0100275 e1_init(0, 0, 0);
Harald Weltee6b0fe82020-12-17 22:22:05 +0100276 _perform_rx_config();
277 _perform_tx_config();
Sylvain Munautbc9f5c42020-09-14 10:22:29 +0200278
Sylvain Munaut96744362022-01-03 17:03:26 +0100279 /* Reset BDI */
Harald Weltee6b0fe82020-12-17 22:22:05 +0100280 g_usb_e1.in_bdi = 0;
Sylvain Munaut96744362022-01-03 17:03:26 +0100281 g_usb_e1.out_bdi = 0;
Harald Weltee6b0fe82020-12-17 22:22:05 +0100282
Sylvain Munautff44f142022-01-03 20:34:23 +0100283 /* EP OUT: Queue two buffers */
284 ep_regs = _get_ep_regs(USB_EP_E1_FB(0));
285 ep_regs->bd[0].csr = USB_BD_STATE_RDY_DATA | USB_BD_LEN(388);
286 ep_regs->bd[1].csr = USB_BD_STATE_RDY_DATA | USB_BD_LEN(388);
Harald Weltee6b0fe82020-12-17 22:22:05 +0100287
Sylvain Munautff44f142022-01-03 20:34:23 +0100288 /* EP Feedback: Pre-fill */
Harald Weltee6b0fe82020-12-17 22:22:05 +0100289 _usb_fill_feedback_ep();
290
Harald Weltee6b0fe82020-12-17 22:22:05 +0100291 break;
Harald Weltee6b0fe82020-12-17 22:22:05 +0100292 }
Harald Welte805f2cf2020-12-14 17:31:03 +0100293
Sylvain Munautbc9f5c42020-09-14 10:22:29 +0200294 return USB_FND_SUCCESS;
295}
296
Harald Weltec8271852020-12-14 13:48:09 +0100297static enum usb_fnd_resp
Sylvain Munautbc9f5c42020-09-14 10:22:29 +0200298_e1_get_intf(const struct usb_intf_desc *base, uint8_t *alt)
299{
Sylvain Munautff44f142022-01-03 20:34:23 +0100300 if ((base->bInterfaceClass != 0xff) || (base->bInterfaceSubClass != 0xe1))
Sylvain Munautbc9f5c42020-09-14 10:22:29 +0200301 return USB_FND_CONTINUE;
302
303 *alt = g_usb_e1.running ? 1 : 0;
304
305 return USB_FND_SUCCESS;
306}
307
Harald Welte9469e042020-12-15 23:09:40 +0100308static bool
309_set_tx_mode_done(struct usb_xfer *xfer)
310{
311 const struct ice1usb_tx_config *cfg = (const struct ice1usb_tx_config *) xfer->data;
312 printf("set_tx_mode %02x%02x%02x%02x\r\n",
313 xfer->data[0], xfer->data[1], xfer->data[2], xfer->data[3]);
314 g_usb_e1.tx_cfg = *cfg;
315 _perform_tx_config();
316 return true;
317}
318
319static bool
320_set_rx_mode_done(struct usb_xfer *xfer)
321{
322 const struct ice1usb_rx_config *cfg = (const struct ice1usb_rx_config *) xfer->data;
323 printf("set_rx_mode %02x\r\n", xfer->data[0]);
324 g_usb_e1.rx_cfg = *cfg;
325 _perform_rx_config();
326 return true;
327}
328
329/* per-interface requests */
330static enum usb_fnd_resp
331_e1_ctrl_req_intf(struct usb_ctrl_req *req, struct usb_xfer *xfer)
332{
333 unsigned int i;
334
335 switch (req->bRequest) {
336 case ICE1USB_INTF_GET_CAPABILITIES:
337 /* no optional capabilities yet */
338 xfer->len = 0;
339 break;
340 case ICE1USB_INTF_SET_TX_CFG:
341 if (req->wLength < sizeof(struct ice1usb_tx_config))
342 return USB_FND_ERROR;
343 xfer->cb_done = _set_tx_mode_done;
344 xfer->cb_ctx = req;
345 xfer->len = sizeof(struct ice1usb_tx_config);
346 break;
347 case ICE1USB_INTF_GET_TX_CFG:
348 if (req->wLength < sizeof(struct ice1usb_tx_config))
349 return USB_FND_ERROR;
350 memcpy(xfer->data, &g_usb_e1.tx_cfg, sizeof(struct ice1usb_tx_config));
351 xfer->len = sizeof(struct ice1usb_tx_config);
352 break;
353 case ICE1USB_INTF_SET_RX_CFG:
354 if (req->wLength < sizeof(struct ice1usb_rx_config))
355 return USB_FND_ERROR;
356 xfer->cb_done = _set_rx_mode_done;
357 xfer->cb_ctx = req;
358 xfer->len = sizeof(struct ice1usb_rx_config);
359 break;
360 case ICE1USB_INTF_GET_RX_CFG:
361 if (req->wLength < sizeof(struct ice1usb_rx_config))
362 return USB_FND_ERROR;
363 memcpy(xfer->data, &g_usb_e1.rx_cfg, sizeof(struct ice1usb_rx_config));
364 xfer->len = sizeof(struct ice1usb_rx_config);
365 break;
366 default:
367 return USB_FND_ERROR;
368 }
369
370 return USB_FND_SUCCESS;
371}
372
373/* device-global requests */
374static enum usb_fnd_resp
375_e1_ctrl_req_dev(struct usb_ctrl_req *req, struct usb_xfer *xfer)
376{
377 switch (req->bRequest) {
378 case ICE1USB_DEV_GET_CAPABILITIES:
379 xfer->data[0] = (1 << ICE1USB_DEV_CAP_GPSDO);
380 xfer->len = 1;
381 break;
382 default:
383 return USB_FND_ERROR;
384 }
385
386 return USB_FND_SUCCESS;
387}
388
389
390/* USB host issues a control request to us */
391static enum usb_fnd_resp
392_e1_ctrl_req(struct usb_ctrl_req *req, struct usb_xfer *xfer)
393{
394 if (USB_REQ_TYPE(req) != USB_REQ_TYPE_VENDOR)
395 return USB_FND_CONTINUE;
396
397 switch (USB_REQ_RCPT(req)) {
398 case USB_REQ_RCPT_DEV:
399 return _e1_ctrl_req_dev(req, xfer);
400 case USB_REQ_RCPT_INTF:
Sylvain Munautff44f142022-01-03 20:34:23 +0100401 if (req->wIndex != USB_INTF_E1(0))
Sylvain Munaut0f40ee02022-01-03 20:33:08 +0100402 return USB_FND_CONTINUE;
Harald Welte9469e042020-12-15 23:09:40 +0100403 return _e1_ctrl_req_intf(req, xfer);
404 case USB_REQ_RCPT_EP:
405 case USB_REQ_RCPT_OTHER:
406 default:
407 return USB_FND_ERROR;
408 }
409}
410
411
Sylvain Munautbc9f5c42020-09-14 10:22:29 +0200412static struct usb_fn_drv _e1_drv = {
413 .set_conf = _e1_set_conf,
414 .set_intf = _e1_set_intf,
415 .get_intf = _e1_get_intf,
Harald Welte9469e042020-12-15 23:09:40 +0100416 .ctrl_req = _e1_ctrl_req,
Sylvain Munautbc9f5c42020-09-14 10:22:29 +0200417};
418
419void
420usb_e1_init(void)
421{
422 memset(&g_usb_e1, 0x00, sizeof(g_usb_e1));
Harald Welte9469e042020-12-15 23:09:40 +0100423 g_usb_e1.tx_cfg = tx_cfg_default;
424 g_usb_e1.rx_cfg = rx_cfg_default;
Sylvain Munautbc9f5c42020-09-14 10:22:29 +0200425 usb_register_function_driver(&_e1_drv);
426}