blob: 3de6071b9e9c04b76fbd09b38ff465bd948a718b [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 */
174 int n = ((csr & USB_BD_LEN_MSK) - 4) / 32;
175 n = e1_tx_feed_data((ptr >> 2) + 1, n);
176
177refill:
178 /* Refill it */
Sylvain Munautff44f142022-01-03 20:34:23 +0100179 ep_regs->bd[bdi].csr = USB_BD_STATE_RDY_DATA | USB_BD_LEN(388);
Sylvain Munautbc9f5c42020-09-14 10:22:29 +0200180
181 /* Next BDI */
182 bdi ^= 1;
183 g_usb_e1.out_bdi = bdi;
184
185 static int x = 0;
186 if ((x++ & 0xff) == 0xff)
187 puts(".");
188 }
189
Sylvain Munautff44f142022-01-03 20:34:23 +0100190 /* Feedback endpoint */
191 ep_regs = _get_ep_regs(USB_EP_E1_FB(0));
192
193 if ((ep_regs->bd[0].csr & USB_BD_STATE_MSK) != USB_BD_STATE_RDY_DATA)
Sylvain Munautbc9f5c42020-09-14 10:22:29 +0200194 {
195 _usb_fill_feedback_ep();
196 }
197}
198
Harald Weltec8271852020-12-14 13:48:09 +0100199static enum usb_fnd_resp
Sylvain Munautbc9f5c42020-09-14 10:22:29 +0200200_e1_set_conf(const struct usb_conf_desc *conf)
201{
202 const struct usb_intf_desc *intf;
203
204 printf("e1 set_conf %08x\n", conf);
205 if (!conf)
206 return USB_FND_SUCCESS;
207
Sylvain Munautff44f142022-01-03 20:34:23 +0100208 intf = usb_desc_find_intf(conf, USB_INTF_E1(0), 0, NULL);
Sylvain Munautbc9f5c42020-09-14 10:22:29 +0200209 if (!intf)
210 return USB_FND_ERROR;
211
212 printf("e1 set_conf %08x\n", intf);
213
Sylvain Munautff44f142022-01-03 20:34:23 +0100214 usb_ep_boot(intf, USB_EP_E1_IN(0), true);
215 usb_ep_boot(intf, USB_EP_E1_OUT(0), true);
216 usb_ep_boot(intf, USB_EP_E1_FB(0), false);
217 usb_ep_boot(intf, USB_EP_E1_INT(0), false);
Sylvain Munautbc9f5c42020-09-14 10:22:29 +0200218
219 return USB_FND_SUCCESS;
220}
221
Harald Welte9469e042020-12-15 23:09:40 +0100222static void _perform_tx_config(void)
223{
224 const struct ice1usb_tx_config *cfg = &g_usb_e1.tx_cfg;
225 e1_tx_config( ((cfg->mode & 3) << 1) |
226 ((cfg->timing & 1) << 3) |
227 ((cfg->alarm & 1) << 4) |
228 ((cfg->ext_loopback & 3) << 5) );
229}
230
231static void _perform_rx_config(void)
232{
233 const struct ice1usb_rx_config *cfg = &g_usb_e1.rx_cfg;
234 e1_rx_config((cfg->mode << 1));
235}
236
Harald Weltec8271852020-12-14 13:48:09 +0100237static enum usb_fnd_resp
Sylvain Munautbc9f5c42020-09-14 10:22:29 +0200238_e1_set_intf(const struct usb_intf_desc *base, const struct usb_intf_desc *sel)
239{
Sylvain Munautff44f142022-01-03 20:34:23 +0100240 volatile struct usb_ep *ep_regs;
241
Sylvain Munaut96744362022-01-03 17:03:26 +0100242 /* Validity checks */
Sylvain Munautff44f142022-01-03 20:34:23 +0100243 if ((base->bInterfaceClass != 0xff) || (base->bInterfaceSubClass != 0xe1))
Sylvain Munautbc9f5c42020-09-14 10:22:29 +0200244 return USB_FND_CONTINUE;
245
Sylvain Munaut96744362022-01-03 17:03:26 +0100246 if (sel->bAlternateSetting > 1)
247 return USB_FND_ERROR;
Sylvain Munautbc9f5c42020-09-14 10:22:29 +0200248
Sylvain Munaut96744362022-01-03 17:03:26 +0100249 /* Don't do anything if no change */
250 if (g_usb_e1.running == (sel->bAlternateSetting != 0))
251 return USB_FND_SUCCESS;
252
253 g_usb_e1.running = (sel->bAlternateSetting != 0);
254
255 /* Reconfigure the endpoints */
Sylvain Munautff44f142022-01-03 20:34:23 +0100256 usb_ep_reconf(sel, USB_EP_E1_IN(0));
257 usb_ep_reconf(sel, USB_EP_E1_OUT(0));
258 usb_ep_reconf(sel, USB_EP_E1_FB(0));
259 usb_ep_reconf(sel, USB_EP_E1_INT(0));
Sylvain Munaut96744362022-01-03 17:03:26 +0100260
261 /* Update E1 and USB state */
262 switch (g_usb_e1.running) {
263 case false:
264 /* Disable E1 rx/tx */
Harald Weltee6b0fe82020-12-17 22:22:05 +0100265 e1_init(0, 0);
Harald Weltee6b0fe82020-12-17 22:22:05 +0100266 break;
Sylvain Munautbc9f5c42020-09-14 10:22:29 +0200267
Sylvain Munaut96744362022-01-03 17:03:26 +0100268 case true:
269 /* Reset and Re-Enable E1 */
270 e1_init(0, 0);
Harald Weltee6b0fe82020-12-17 22:22:05 +0100271 _perform_rx_config();
272 _perform_tx_config();
Sylvain Munautbc9f5c42020-09-14 10:22:29 +0200273
Sylvain Munaut96744362022-01-03 17:03:26 +0100274 /* Reset BDI */
Harald Weltee6b0fe82020-12-17 22:22:05 +0100275 g_usb_e1.in_bdi = 0;
Sylvain Munaut96744362022-01-03 17:03:26 +0100276 g_usb_e1.out_bdi = 0;
Harald Weltee6b0fe82020-12-17 22:22:05 +0100277
Sylvain Munautff44f142022-01-03 20:34:23 +0100278 /* EP OUT: Queue two buffers */
279 ep_regs = _get_ep_regs(USB_EP_E1_FB(0));
280 ep_regs->bd[0].csr = USB_BD_STATE_RDY_DATA | USB_BD_LEN(388);
281 ep_regs->bd[1].csr = USB_BD_STATE_RDY_DATA | USB_BD_LEN(388);
Harald Weltee6b0fe82020-12-17 22:22:05 +0100282
Sylvain Munautff44f142022-01-03 20:34:23 +0100283 /* EP Feedback: Pre-fill */
Harald Weltee6b0fe82020-12-17 22:22:05 +0100284 _usb_fill_feedback_ep();
285
Harald Weltee6b0fe82020-12-17 22:22:05 +0100286 break;
Harald Weltee6b0fe82020-12-17 22:22:05 +0100287 }
Harald Welte805f2cf2020-12-14 17:31:03 +0100288
Sylvain Munautbc9f5c42020-09-14 10:22:29 +0200289 return USB_FND_SUCCESS;
290}
291
Harald Weltec8271852020-12-14 13:48:09 +0100292static enum usb_fnd_resp
Sylvain Munautbc9f5c42020-09-14 10:22:29 +0200293_e1_get_intf(const struct usb_intf_desc *base, uint8_t *alt)
294{
Sylvain Munautff44f142022-01-03 20:34:23 +0100295 if ((base->bInterfaceClass != 0xff) || (base->bInterfaceSubClass != 0xe1))
Sylvain Munautbc9f5c42020-09-14 10:22:29 +0200296 return USB_FND_CONTINUE;
297
298 *alt = g_usb_e1.running ? 1 : 0;
299
300 return USB_FND_SUCCESS;
301}
302
Harald Welte9469e042020-12-15 23:09:40 +0100303static bool
304_set_tx_mode_done(struct usb_xfer *xfer)
305{
306 const struct ice1usb_tx_config *cfg = (const struct ice1usb_tx_config *) xfer->data;
307 printf("set_tx_mode %02x%02x%02x%02x\r\n",
308 xfer->data[0], xfer->data[1], xfer->data[2], xfer->data[3]);
309 g_usb_e1.tx_cfg = *cfg;
310 _perform_tx_config();
311 return true;
312}
313
314static bool
315_set_rx_mode_done(struct usb_xfer *xfer)
316{
317 const struct ice1usb_rx_config *cfg = (const struct ice1usb_rx_config *) xfer->data;
318 printf("set_rx_mode %02x\r\n", xfer->data[0]);
319 g_usb_e1.rx_cfg = *cfg;
320 _perform_rx_config();
321 return true;
322}
323
324/* per-interface requests */
325static enum usb_fnd_resp
326_e1_ctrl_req_intf(struct usb_ctrl_req *req, struct usb_xfer *xfer)
327{
328 unsigned int i;
329
330 switch (req->bRequest) {
331 case ICE1USB_INTF_GET_CAPABILITIES:
332 /* no optional capabilities yet */
333 xfer->len = 0;
334 break;
335 case ICE1USB_INTF_SET_TX_CFG:
336 if (req->wLength < sizeof(struct ice1usb_tx_config))
337 return USB_FND_ERROR;
338 xfer->cb_done = _set_tx_mode_done;
339 xfer->cb_ctx = req;
340 xfer->len = sizeof(struct ice1usb_tx_config);
341 break;
342 case ICE1USB_INTF_GET_TX_CFG:
343 if (req->wLength < sizeof(struct ice1usb_tx_config))
344 return USB_FND_ERROR;
345 memcpy(xfer->data, &g_usb_e1.tx_cfg, sizeof(struct ice1usb_tx_config));
346 xfer->len = sizeof(struct ice1usb_tx_config);
347 break;
348 case ICE1USB_INTF_SET_RX_CFG:
349 if (req->wLength < sizeof(struct ice1usb_rx_config))
350 return USB_FND_ERROR;
351 xfer->cb_done = _set_rx_mode_done;
352 xfer->cb_ctx = req;
353 xfer->len = sizeof(struct ice1usb_rx_config);
354 break;
355 case ICE1USB_INTF_GET_RX_CFG:
356 if (req->wLength < sizeof(struct ice1usb_rx_config))
357 return USB_FND_ERROR;
358 memcpy(xfer->data, &g_usb_e1.rx_cfg, sizeof(struct ice1usb_rx_config));
359 xfer->len = sizeof(struct ice1usb_rx_config);
360 break;
361 default:
362 return USB_FND_ERROR;
363 }
364
365 return USB_FND_SUCCESS;
366}
367
368/* device-global requests */
369static enum usb_fnd_resp
370_e1_ctrl_req_dev(struct usb_ctrl_req *req, struct usb_xfer *xfer)
371{
372 switch (req->bRequest) {
373 case ICE1USB_DEV_GET_CAPABILITIES:
374 xfer->data[0] = (1 << ICE1USB_DEV_CAP_GPSDO);
375 xfer->len = 1;
376 break;
377 default:
378 return USB_FND_ERROR;
379 }
380
381 return USB_FND_SUCCESS;
382}
383
384
385/* USB host issues a control request to us */
386static enum usb_fnd_resp
387_e1_ctrl_req(struct usb_ctrl_req *req, struct usb_xfer *xfer)
388{
389 if (USB_REQ_TYPE(req) != USB_REQ_TYPE_VENDOR)
390 return USB_FND_CONTINUE;
391
392 switch (USB_REQ_RCPT(req)) {
393 case USB_REQ_RCPT_DEV:
394 return _e1_ctrl_req_dev(req, xfer);
395 case USB_REQ_RCPT_INTF:
Sylvain Munautff44f142022-01-03 20:34:23 +0100396 if (req->wIndex != USB_INTF_E1(0))
Sylvain Munaut0f40ee02022-01-03 20:33:08 +0100397 return USB_FND_CONTINUE;
Harald Welte9469e042020-12-15 23:09:40 +0100398 return _e1_ctrl_req_intf(req, xfer);
399 case USB_REQ_RCPT_EP:
400 case USB_REQ_RCPT_OTHER:
401 default:
402 return USB_FND_ERROR;
403 }
404}
405
406
Sylvain Munautbc9f5c42020-09-14 10:22:29 +0200407static struct usb_fn_drv _e1_drv = {
408 .set_conf = _e1_set_conf,
409 .set_intf = _e1_set_intf,
410 .get_intf = _e1_get_intf,
Harald Welte9469e042020-12-15 23:09:40 +0100411 .ctrl_req = _e1_ctrl_req,
Sylvain Munautbc9f5c42020-09-14 10:22:29 +0200412};
413
414void
415usb_e1_init(void)
416{
417 memset(&g_usb_e1, 0x00, sizeof(g_usb_e1));
Harald Welte9469e042020-12-15 23:09:40 +0100418 g_usb_e1.tx_cfg = tx_cfg_default;
419 g_usb_e1.rx_cfg = rx_cfg_default;
Sylvain Munautbc9f5c42020-09-14 10:22:29 +0200420 usb_register_function_driver(&_e1_drv);
421}