blob: e180fec0b3eca5b986cf944b51435af18e6bfc76 [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"
16#include "misc.h"
Harald Welte2df1f802020-12-14 17:46:53 +010017#include "e1.h"
Harald Welte9469e042020-12-15 23:09:40 +010018#include "e1_hw.h"
19
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
44/* Hack */
Harald Weltedaff4f62020-12-14 17:39:23 +010045unsigned int e1_rx_need_data(unsigned int usb_addr, unsigned int max_len, unsigned int *pos);
Sylvain Munautbc9f5c42020-09-14 10:22:29 +020046unsigned int e1_tx_feed_data(unsigned int usb_addr, unsigned int len);
47unsigned int e1_tx_level(void);
48unsigned int e1_rx_level(void);
49/* ---- */
50
Sylvain Munautbc9f5c42020-09-14 10:22:29 +020051static void
52_usb_fill_feedback_ep(void)
53{
54 static uint16_t ticks_prev = 0;
55 uint16_t ticks;
56 uint32_t val = 8192;
57 unsigned int level;
58
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 */
74 usb_data_write(64, &val, 4);
75 usb_ep_regs[1].in.bd[0].ptr = 64;
76 usb_ep_regs[1].in.bd[0].csr = USB_BD_STATE_RDY_DATA | USB_BD_LEN(3);
77}
78
79
80void
81usb_e1_run(void)
82{
83 int bdi;
84
85 if (!g_usb_e1.running)
86 return;
87
Harald Welte805f2cf2020-12-14 17:31:03 +010088 /* EP3 IRQ */
89 if ((usb_ep_regs[3].in.bd[0].csr & USB_BD_STATE_MSK) != USB_BD_STATE_RDY_DATA) {
90 const struct e1_error_count *cur_err = e1_get_error_count();
91 if (memcmp(cur_err, &g_usb_e1.last_err, sizeof(*cur_err))) {
92 struct ice1usb_irq errmsg = {
93 .type = ICE1USB_IRQ_T_ERRCNT,
94 .u = {
95 .errors = {
96 .crc = cur_err->crc,
97 .align = cur_err->align,
98 .ovfl = cur_err->ovfl,
99 .unfl = cur_err->unfl,
100 .flags = cur_err->flags,
101 }
102 }
103 };
104 printf("E");
105 usb_data_write(usb_ep_regs[3].in.bd[0].ptr, &errmsg, sizeof(errmsg));
106 usb_ep_regs[3].in.bd[0].csr = USB_BD_STATE_RDY_DATA | USB_BD_LEN(sizeof(errmsg));
107 g_usb_e1.last_err = *cur_err;
108 }
109 }
110
Sylvain Munautbc9f5c42020-09-14 10:22:29 +0200111 /* EP2 IN */
112 bdi = g_usb_e1.in_bdi;
113
114 while ((usb_ep_regs[2].in.bd[bdi].csr & USB_BD_STATE_MSK) != USB_BD_STATE_RDY_DATA)
115 {
116 uint32_t ptr = usb_ep_regs[2].in.bd[bdi].ptr;
117 uint32_t hdr;
Harald Welte2df1f802020-12-14 17:46:53 +0100118 unsigned int pos;
Sylvain Munautbc9f5c42020-09-14 10:22:29 +0200119
120 /* Error check */
121 if ((usb_ep_regs[2].in.bd[bdi].csr & USB_BD_STATE_MSK) == USB_BD_STATE_DONE_ERR)
122 puts("Err EP2 IN\n");
123
124 /* Get some data from E1 */
125 int n = e1_rx_level();
126
127 if (n > 64)
128 n = 12;
129 else if (n > 32)
130 n = 10;
131 else if (n > 8)
132 n = 8;
133 else if (!n)
134 break;
135
Harald Welte2df1f802020-12-14 17:46:53 +0100136 n = e1_rx_need_data((ptr >> 2) + 1, n, &pos);
Sylvain Munautbc9f5c42020-09-14 10:22:29 +0200137
Harald Welte2df1f802020-12-14 17:46:53 +0100138 /* Write header: currently version and pos (mfr/fr number) */
139 hdr = (0 << 28) | (pos & 0xff);
Sylvain Munautbc9f5c42020-09-14 10:22:29 +0200140 usb_data_write(ptr, &hdr, 4);
141
142 /* Resubmit */
143 usb_ep_regs[2].in.bd[bdi].csr = USB_BD_STATE_RDY_DATA | USB_BD_LEN((n * 32) + 4);
144
145 /* Next BDI */
146 bdi ^= 1;
147 g_usb_e1.in_bdi = bdi;
148 }
149
150 /* EP1 OUT */
151 bdi = g_usb_e1.out_bdi;
152
153 while ((usb_ep_regs[1].out.bd[bdi].csr & USB_BD_STATE_MSK) != USB_BD_STATE_RDY_DATA)
154 {
155 uint32_t ptr = usb_ep_regs[1].out.bd[bdi].ptr;
156 uint32_t csr = usb_ep_regs[1].out.bd[bdi].csr;
157 uint32_t hdr;
158
159 /* Error check */
160 if ((csr & USB_BD_STATE_MSK) == USB_BD_STATE_DONE_ERR) {
161 puts("Err EP1 OUT\n");
162 goto refill;
163 }
164
165 /* Grab header */
166 usb_data_read(&hdr, ptr, 4);
167
168 /* Empty data into the FIFO */
169 int n = ((csr & USB_BD_LEN_MSK) - 4) / 32;
170 n = e1_tx_feed_data((ptr >> 2) + 1, n);
171
172refill:
173 /* Refill it */
174 usb_ep_regs[1].out.bd[bdi].csr = USB_BD_STATE_RDY_DATA | USB_BD_LEN(388);
175
176 /* Next BDI */
177 bdi ^= 1;
178 g_usb_e1.out_bdi = bdi;
179
180 static int x = 0;
181 if ((x++ & 0xff) == 0xff)
182 puts(".");
183 }
184
185 /* EP1 IN */
186 if ((usb_ep_regs[1].in.bd[0].csr & USB_BD_STATE_MSK) != USB_BD_STATE_RDY_DATA)
187 {
188 _usb_fill_feedback_ep();
189 }
190}
191
192static const struct usb_intf_desc *
193_find_intf(const struct usb_conf_desc *conf, uint8_t idx)
194{
195 const struct usb_intf_desc *intf = NULL;
196 const void *sod, *eod;
197
198 if (!conf)
199 return NULL;
200
201 sod = conf;
202 eod = sod + conf->wTotalLength;
203
204 while (1) {
205 sod = usb_desc_find(sod, eod, USB_DT_INTF);
206 if (!sod)
207 break;
208
209 intf = (void*)sod;
210 if (intf->bInterfaceNumber == idx)
211 return intf;
212
213 sod = usb_desc_next(sod);
214 }
215
216 return NULL;
217}
Harald Weltec8271852020-12-14 13:48:09 +0100218
219static enum usb_fnd_resp
Sylvain Munautbc9f5c42020-09-14 10:22:29 +0200220_e1_set_conf(const struct usb_conf_desc *conf)
221{
222 const struct usb_intf_desc *intf;
223
224 printf("e1 set_conf %08x\n", conf);
225 if (!conf)
226 return USB_FND_SUCCESS;
227
228 intf = _find_intf(conf, 0);
229 if (!intf)
230 return USB_FND_ERROR;
231
232 printf("e1 set_conf %08x\n", intf);
233
234 usb_ep_boot(intf, 0x01, true);
235 usb_ep_boot(intf, 0x81, true);
236 usb_ep_boot(intf, 0x82, true);
Harald Welte805f2cf2020-12-14 17:31:03 +0100237 usb_ep_boot(intf, 0x83, true);
Sylvain Munautbc9f5c42020-09-14 10:22:29 +0200238
239 return USB_FND_SUCCESS;
240}
241
Harald Welte9469e042020-12-15 23:09:40 +0100242static void _perform_tx_config(void)
243{
244 const struct ice1usb_tx_config *cfg = &g_usb_e1.tx_cfg;
245 e1_tx_config( ((cfg->mode & 3) << 1) |
246 ((cfg->timing & 1) << 3) |
247 ((cfg->alarm & 1) << 4) |
248 ((cfg->ext_loopback & 3) << 5) );
249}
250
251static void _perform_rx_config(void)
252{
253 const struct ice1usb_rx_config *cfg = &g_usb_e1.rx_cfg;
254 e1_rx_config((cfg->mode << 1));
255}
256
Harald Weltec8271852020-12-14 13:48:09 +0100257static enum usb_fnd_resp
Sylvain Munautbc9f5c42020-09-14 10:22:29 +0200258_e1_set_intf(const struct usb_intf_desc *base, const struct usb_intf_desc *sel)
259{
260 if (base->bInterfaceNumber != 0)
261 return USB_FND_CONTINUE;
262
Harald Weltee6b0fe82020-12-17 22:22:05 +0100263 switch (sel->bAlternateSetting) {
264 case 0:
265 if (!g_usb_e1.running)
266 return USB_FND_SUCCESS;
Sylvain Munautbc9f5c42020-09-14 10:22:29 +0200267
Harald Weltee6b0fe82020-12-17 22:22:05 +0100268 /* disable E1 rx/tx */
269 e1_init(0, 0);
Sylvain Munautbc9f5c42020-09-14 10:22:29 +0200270
Harald Weltee6b0fe82020-12-17 22:22:05 +0100271 /* EP1 OUT */
272 usb_ep_regs[1].out.bd[0].csr = 0;
273 usb_ep_regs[1].out.bd[1].csr = 0;
Harald Welte9469e042020-12-15 23:09:40 +0100274
Harald Weltee6b0fe82020-12-17 22:22:05 +0100275 /* EP1 IN (feedback) */
276 usb_ep_regs[1].in.bd[0].csr = 0;
Sylvain Munautbc9f5c42020-09-14 10:22:29 +0200277
Harald Weltee6b0fe82020-12-17 22:22:05 +0100278 /* EP2 IN (data) */
279 usb_ep_regs[2].in.bd[0].csr = 0;
280 usb_ep_regs[2].in.bd[1].csr = 0;
Sylvain Munautbc9f5c42020-09-14 10:22:29 +0200281
Harald Weltee6b0fe82020-12-17 22:22:05 +0100282 /* EP3 IN: Interrupt */
283 usb_ep_regs[3].in.bd[0].csr = 0;
Sylvain Munautbc9f5c42020-09-14 10:22:29 +0200284
Harald Weltee6b0fe82020-12-17 22:22:05 +0100285 g_usb_e1.running = false;
286 break;
287 case 1:
288 /* Hack to avoid re-setting while running ... avoid BD desync */
289 if (g_usb_e1.running)
290 return USB_FND_SUCCESS;
Sylvain Munautbc9f5c42020-09-14 10:22:29 +0200291
Harald Weltee6b0fe82020-12-17 22:22:05 +0100292 _perform_rx_config();
293 _perform_tx_config();
Sylvain Munautbc9f5c42020-09-14 10:22:29 +0200294
Harald Weltee6b0fe82020-12-17 22:22:05 +0100295 g_usb_e1.running = true;
Sylvain Munautbc9f5c42020-09-14 10:22:29 +0200296
Harald Weltee6b0fe82020-12-17 22:22:05 +0100297 /* Configure EP1 OUT / EP2 IN */
298 usb_ep_regs[1].out.status = USB_EP_TYPE_ISOC | USB_EP_BD_DUAL; /* Type=Isochronous, dual buffered */
299 usb_ep_regs[2].in.status = USB_EP_TYPE_ISOC | USB_EP_BD_DUAL; /* Type=Isochronous, dual buffered */
Sylvain Munautbc9f5c42020-09-14 10:22:29 +0200300
Harald Weltee6b0fe82020-12-17 22:22:05 +0100301 /* Configure EP1 IN (feedback) */
302 usb_ep_regs[1].in.status = USB_EP_TYPE_ISOC; /* Type=Isochronous, single buffered */
Sylvain Munautbc9f5c42020-09-14 10:22:29 +0200303
Harald Weltee6b0fe82020-12-17 22:22:05 +0100304 /* EP2 IN: Prepare two buffers */
305 g_usb_e1.in_bdi = 0;
306 usb_ep_regs[2].in.bd[0].ptr = 1024;
307 usb_ep_regs[2].in.bd[0].csr = 0;
308
309 usb_ep_regs[2].in.bd[1].ptr = 1536;
310 usb_ep_regs[2].in.bd[1].csr = 0;
311
312 /* EP1 OUT: Queue two buffers */
313 g_usb_e1.out_bdi = 0;
314 usb_ep_regs[1].out.bd[0].ptr = 1024;
315 usb_ep_regs[1].out.bd[0].csr = USB_BD_STATE_RDY_DATA | USB_BD_LEN(388);
316
317 usb_ep_regs[1].out.bd[1].ptr = 1536;
318 usb_ep_regs[1].out.bd[1].csr = USB_BD_STATE_RDY_DATA | USB_BD_LEN(388);
319
320 /* EP1 IN: Queue buffer */
321 _usb_fill_feedback_ep();
322
323 /* EP3 IN: Interrupt */
324 usb_ep_regs[3].in.status = USB_EP_TYPE_INT;
325 usb_ep_regs[3].in.bd[0].ptr = 68;
326 usb_ep_regs[3].in.bd[0].csr = 0;
327 break;
328 default:
329 return USB_FND_ERROR;
330 }
Harald Welte805f2cf2020-12-14 17:31:03 +0100331
Sylvain Munautbc9f5c42020-09-14 10:22:29 +0200332 return USB_FND_SUCCESS;
333}
334
Harald Weltec8271852020-12-14 13:48:09 +0100335static enum usb_fnd_resp
Sylvain Munautbc9f5c42020-09-14 10:22:29 +0200336_e1_get_intf(const struct usb_intf_desc *base, uint8_t *alt)
337{
338 if (base->bInterfaceNumber != 0)
339 return USB_FND_CONTINUE;
340
341 *alt = g_usb_e1.running ? 1 : 0;
342
343 return USB_FND_SUCCESS;
344}
345
Harald Welte9469e042020-12-15 23:09:40 +0100346static bool
347_set_tx_mode_done(struct usb_xfer *xfer)
348{
349 const struct ice1usb_tx_config *cfg = (const struct ice1usb_tx_config *) xfer->data;
350 printf("set_tx_mode %02x%02x%02x%02x\r\n",
351 xfer->data[0], xfer->data[1], xfer->data[2], xfer->data[3]);
352 g_usb_e1.tx_cfg = *cfg;
353 _perform_tx_config();
354 return true;
355}
356
357static bool
358_set_rx_mode_done(struct usb_xfer *xfer)
359{
360 const struct ice1usb_rx_config *cfg = (const struct ice1usb_rx_config *) xfer->data;
361 printf("set_rx_mode %02x\r\n", xfer->data[0]);
362 g_usb_e1.rx_cfg = *cfg;
363 _perform_rx_config();
364 return true;
365}
366
367/* per-interface requests */
368static enum usb_fnd_resp
369_e1_ctrl_req_intf(struct usb_ctrl_req *req, struct usb_xfer *xfer)
370{
371 unsigned int i;
372
373 switch (req->bRequest) {
374 case ICE1USB_INTF_GET_CAPABILITIES:
375 /* no optional capabilities yet */
376 xfer->len = 0;
377 break;
378 case ICE1USB_INTF_SET_TX_CFG:
379 if (req->wLength < sizeof(struct ice1usb_tx_config))
380 return USB_FND_ERROR;
381 xfer->cb_done = _set_tx_mode_done;
382 xfer->cb_ctx = req;
383 xfer->len = sizeof(struct ice1usb_tx_config);
384 break;
385 case ICE1USB_INTF_GET_TX_CFG:
386 if (req->wLength < sizeof(struct ice1usb_tx_config))
387 return USB_FND_ERROR;
388 memcpy(xfer->data, &g_usb_e1.tx_cfg, sizeof(struct ice1usb_tx_config));
389 xfer->len = sizeof(struct ice1usb_tx_config);
390 break;
391 case ICE1USB_INTF_SET_RX_CFG:
392 if (req->wLength < sizeof(struct ice1usb_rx_config))
393 return USB_FND_ERROR;
394 xfer->cb_done = _set_rx_mode_done;
395 xfer->cb_ctx = req;
396 xfer->len = sizeof(struct ice1usb_rx_config);
397 break;
398 case ICE1USB_INTF_GET_RX_CFG:
399 if (req->wLength < sizeof(struct ice1usb_rx_config))
400 return USB_FND_ERROR;
401 memcpy(xfer->data, &g_usb_e1.rx_cfg, sizeof(struct ice1usb_rx_config));
402 xfer->len = sizeof(struct ice1usb_rx_config);
403 break;
404 default:
405 return USB_FND_ERROR;
406 }
407
408 return USB_FND_SUCCESS;
409}
410
411/* device-global requests */
412static enum usb_fnd_resp
413_e1_ctrl_req_dev(struct usb_ctrl_req *req, struct usb_xfer *xfer)
414{
415 switch (req->bRequest) {
416 case ICE1USB_DEV_GET_CAPABILITIES:
417 xfer->data[0] = (1 << ICE1USB_DEV_CAP_GPSDO);
418 xfer->len = 1;
419 break;
420 default:
421 return USB_FND_ERROR;
422 }
423
424 return USB_FND_SUCCESS;
425}
426
427
428/* USB host issues a control request to us */
429static enum usb_fnd_resp
430_e1_ctrl_req(struct usb_ctrl_req *req, struct usb_xfer *xfer)
431{
432 if (USB_REQ_TYPE(req) != USB_REQ_TYPE_VENDOR)
433 return USB_FND_CONTINUE;
434
435 switch (USB_REQ_RCPT(req)) {
436 case USB_REQ_RCPT_DEV:
437 return _e1_ctrl_req_dev(req, xfer);
438 case USB_REQ_RCPT_INTF:
439 if (req->wIndex != 0)
440 return USB_FND_ERROR;
441 return _e1_ctrl_req_intf(req, xfer);
442 case USB_REQ_RCPT_EP:
443 case USB_REQ_RCPT_OTHER:
444 default:
445 return USB_FND_ERROR;
446 }
447}
448
449
Sylvain Munautbc9f5c42020-09-14 10:22:29 +0200450static struct usb_fn_drv _e1_drv = {
451 .set_conf = _e1_set_conf,
452 .set_intf = _e1_set_intf,
453 .get_intf = _e1_get_intf,
Harald Welte9469e042020-12-15 23:09:40 +0100454 .ctrl_req = _e1_ctrl_req,
Sylvain Munautbc9f5c42020-09-14 10:22:29 +0200455};
456
457void
458usb_e1_init(void)
459{
460 memset(&g_usb_e1, 0x00, sizeof(g_usb_e1));
Harald Welte9469e042020-12-15 23:09:40 +0100461 g_usb_e1.tx_cfg = tx_cfg_default;
462 g_usb_e1.rx_cfg = rx_cfg_default;
Sylvain Munautbc9f5c42020-09-14 10:22:29 +0200463 usb_register_function_driver(&_e1_drv);
464}