blob: ed4826fb50e5e866a6cb43938ba8673b1438064d [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 Munautbc9f5c42020-09-14 10:22:29 +020060 ticks = e1_tick_read();
61 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 */
67 level = e1_tx_level();
68 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) {
Harald Welte805f2cf2020-12-14 17:31:03 +010093 const struct e1_error_count *cur_err = e1_get_error_count();
94 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 */
129 int n = e1_rx_level();
130
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
Harald Welte2df1f802020-12-14 17:46:53 +0100140 n = e1_rx_need_data((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)
176 e1_tx_feed_data((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;
226 e1_tx_config( ((cfg->mode & 3) << 1) |
227 ((cfg->timing & 1) << 3) |
228 ((cfg->alarm & 1) << 4) |
229 ((cfg->ext_loopback & 3) << 5) );
230}
231
232static void _perform_rx_config(void)
233{
234 const struct ice1usb_rx_config *cfg = &g_usb_e1.rx_cfg;
235 e1_rx_config((cfg->mode << 1));
236}
237
Harald Weltec8271852020-12-14 13:48:09 +0100238static enum usb_fnd_resp
Sylvain Munautbc9f5c42020-09-14 10:22:29 +0200239_e1_set_intf(const struct usb_intf_desc *base, const struct usb_intf_desc *sel)
240{
Sylvain Munautff44f142022-01-03 20:34:23 +0100241 volatile struct usb_ep *ep_regs;
242
Sylvain Munaut96744362022-01-03 17:03:26 +0100243 /* Validity checks */
Sylvain Munautff44f142022-01-03 20:34:23 +0100244 if ((base->bInterfaceClass != 0xff) || (base->bInterfaceSubClass != 0xe1))
Sylvain Munautbc9f5c42020-09-14 10:22:29 +0200245 return USB_FND_CONTINUE;
246
Sylvain Munaut96744362022-01-03 17:03:26 +0100247 if (sel->bAlternateSetting > 1)
248 return USB_FND_ERROR;
Sylvain Munautbc9f5c42020-09-14 10:22:29 +0200249
Sylvain Munaut96744362022-01-03 17:03:26 +0100250 /* Don't do anything if no change */
251 if (g_usb_e1.running == (sel->bAlternateSetting != 0))
252 return USB_FND_SUCCESS;
253
254 g_usb_e1.running = (sel->bAlternateSetting != 0);
255
256 /* Reconfigure the endpoints */
Sylvain Munautff44f142022-01-03 20:34:23 +0100257 usb_ep_reconf(sel, USB_EP_E1_IN(0));
258 usb_ep_reconf(sel, USB_EP_E1_OUT(0));
259 usb_ep_reconf(sel, USB_EP_E1_FB(0));
260 usb_ep_reconf(sel, USB_EP_E1_INT(0));
Sylvain Munaut96744362022-01-03 17:03:26 +0100261
262 /* Update E1 and USB state */
263 switch (g_usb_e1.running) {
264 case false:
265 /* Disable E1 rx/tx */
Harald Weltee6b0fe82020-12-17 22:22:05 +0100266 e1_init(0, 0);
Harald Weltee6b0fe82020-12-17 22:22:05 +0100267 break;
Sylvain Munautbc9f5c42020-09-14 10:22:29 +0200268
Sylvain Munaut96744362022-01-03 17:03:26 +0100269 case true:
270 /* Reset and Re-Enable E1 */
271 e1_init(0, 0);
Harald Weltee6b0fe82020-12-17 22:22:05 +0100272 _perform_rx_config();
273 _perform_tx_config();
Sylvain Munautbc9f5c42020-09-14 10:22:29 +0200274
Sylvain Munaut96744362022-01-03 17:03:26 +0100275 /* Reset BDI */
Harald Weltee6b0fe82020-12-17 22:22:05 +0100276 g_usb_e1.in_bdi = 0;
Sylvain Munaut96744362022-01-03 17:03:26 +0100277 g_usb_e1.out_bdi = 0;
Harald Weltee6b0fe82020-12-17 22:22:05 +0100278
Sylvain Munautff44f142022-01-03 20:34:23 +0100279 /* EP OUT: Queue two buffers */
280 ep_regs = _get_ep_regs(USB_EP_E1_FB(0));
281 ep_regs->bd[0].csr = USB_BD_STATE_RDY_DATA | USB_BD_LEN(388);
282 ep_regs->bd[1].csr = USB_BD_STATE_RDY_DATA | USB_BD_LEN(388);
Harald Weltee6b0fe82020-12-17 22:22:05 +0100283
Sylvain Munautff44f142022-01-03 20:34:23 +0100284 /* EP Feedback: Pre-fill */
Harald Weltee6b0fe82020-12-17 22:22:05 +0100285 _usb_fill_feedback_ep();
286
Harald Weltee6b0fe82020-12-17 22:22:05 +0100287 break;
Harald Weltee6b0fe82020-12-17 22:22:05 +0100288 }
Harald Welte805f2cf2020-12-14 17:31:03 +0100289
Sylvain Munautbc9f5c42020-09-14 10:22:29 +0200290 return USB_FND_SUCCESS;
291}
292
Harald Weltec8271852020-12-14 13:48:09 +0100293static enum usb_fnd_resp
Sylvain Munautbc9f5c42020-09-14 10:22:29 +0200294_e1_get_intf(const struct usb_intf_desc *base, uint8_t *alt)
295{
Sylvain Munautff44f142022-01-03 20:34:23 +0100296 if ((base->bInterfaceClass != 0xff) || (base->bInterfaceSubClass != 0xe1))
Sylvain Munautbc9f5c42020-09-14 10:22:29 +0200297 return USB_FND_CONTINUE;
298
299 *alt = g_usb_e1.running ? 1 : 0;
300
301 return USB_FND_SUCCESS;
302}
303
Harald Welte9469e042020-12-15 23:09:40 +0100304static bool
305_set_tx_mode_done(struct usb_xfer *xfer)
306{
307 const struct ice1usb_tx_config *cfg = (const struct ice1usb_tx_config *) xfer->data;
308 printf("set_tx_mode %02x%02x%02x%02x\r\n",
309 xfer->data[0], xfer->data[1], xfer->data[2], xfer->data[3]);
310 g_usb_e1.tx_cfg = *cfg;
311 _perform_tx_config();
312 return true;
313}
314
315static bool
316_set_rx_mode_done(struct usb_xfer *xfer)
317{
318 const struct ice1usb_rx_config *cfg = (const struct ice1usb_rx_config *) xfer->data;
319 printf("set_rx_mode %02x\r\n", xfer->data[0]);
320 g_usb_e1.rx_cfg = *cfg;
321 _perform_rx_config();
322 return true;
323}
324
325/* per-interface requests */
326static enum usb_fnd_resp
327_e1_ctrl_req_intf(struct usb_ctrl_req *req, struct usb_xfer *xfer)
328{
329 unsigned int i;
330
331 switch (req->bRequest) {
332 case ICE1USB_INTF_GET_CAPABILITIES:
333 /* no optional capabilities yet */
334 xfer->len = 0;
335 break;
336 case ICE1USB_INTF_SET_TX_CFG:
337 if (req->wLength < sizeof(struct ice1usb_tx_config))
338 return USB_FND_ERROR;
339 xfer->cb_done = _set_tx_mode_done;
340 xfer->cb_ctx = req;
341 xfer->len = sizeof(struct ice1usb_tx_config);
342 break;
343 case ICE1USB_INTF_GET_TX_CFG:
344 if (req->wLength < sizeof(struct ice1usb_tx_config))
345 return USB_FND_ERROR;
346 memcpy(xfer->data, &g_usb_e1.tx_cfg, sizeof(struct ice1usb_tx_config));
347 xfer->len = sizeof(struct ice1usb_tx_config);
348 break;
349 case ICE1USB_INTF_SET_RX_CFG:
350 if (req->wLength < sizeof(struct ice1usb_rx_config))
351 return USB_FND_ERROR;
352 xfer->cb_done = _set_rx_mode_done;
353 xfer->cb_ctx = req;
354 xfer->len = sizeof(struct ice1usb_rx_config);
355 break;
356 case ICE1USB_INTF_GET_RX_CFG:
357 if (req->wLength < sizeof(struct ice1usb_rx_config))
358 return USB_FND_ERROR;
359 memcpy(xfer->data, &g_usb_e1.rx_cfg, sizeof(struct ice1usb_rx_config));
360 xfer->len = sizeof(struct ice1usb_rx_config);
361 break;
362 default:
363 return USB_FND_ERROR;
364 }
365
366 return USB_FND_SUCCESS;
367}
368
369/* device-global requests */
370static enum usb_fnd_resp
371_e1_ctrl_req_dev(struct usb_ctrl_req *req, struct usb_xfer *xfer)
372{
373 switch (req->bRequest) {
374 case ICE1USB_DEV_GET_CAPABILITIES:
375 xfer->data[0] = (1 << ICE1USB_DEV_CAP_GPSDO);
376 xfer->len = 1;
377 break;
378 default:
379 return USB_FND_ERROR;
380 }
381
382 return USB_FND_SUCCESS;
383}
384
385
386/* USB host issues a control request to us */
387static enum usb_fnd_resp
388_e1_ctrl_req(struct usb_ctrl_req *req, struct usb_xfer *xfer)
389{
390 if (USB_REQ_TYPE(req) != USB_REQ_TYPE_VENDOR)
391 return USB_FND_CONTINUE;
392
393 switch (USB_REQ_RCPT(req)) {
394 case USB_REQ_RCPT_DEV:
395 return _e1_ctrl_req_dev(req, xfer);
396 case USB_REQ_RCPT_INTF:
Sylvain Munautff44f142022-01-03 20:34:23 +0100397 if (req->wIndex != USB_INTF_E1(0))
Sylvain Munaut0f40ee02022-01-03 20:33:08 +0100398 return USB_FND_CONTINUE;
Harald Welte9469e042020-12-15 23:09:40 +0100399 return _e1_ctrl_req_intf(req, xfer);
400 case USB_REQ_RCPT_EP:
401 case USB_REQ_RCPT_OTHER:
402 default:
403 return USB_FND_ERROR;
404 }
405}
406
407
Sylvain Munautbc9f5c42020-09-14 10:22:29 +0200408static struct usb_fn_drv _e1_drv = {
409 .set_conf = _e1_set_conf,
410 .set_intf = _e1_set_intf,
411 .get_intf = _e1_get_intf,
Harald Welte9469e042020-12-15 23:09:40 +0100412 .ctrl_req = _e1_ctrl_req,
Sylvain Munautbc9f5c42020-09-14 10:22:29 +0200413};
414
415void
416usb_e1_init(void)
417{
418 memset(&g_usb_e1, 0x00, sizeof(g_usb_e1));
Harald Welte9469e042020-12-15 23:09:40 +0100419 g_usb_e1.tx_cfg = tx_cfg_default;
420 g_usb_e1.rx_cfg = rx_cfg_default;
Sylvain Munautbc9f5c42020-09-14 10:22:29 +0200421 usb_register_function_driver(&_e1_drv);
422}