blob: d90e405de8e37ceb81ed2953a32063629214e39e [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 Welte394b6802020-12-14 17:46:53 +010017#include "e1.h"
Sylvain Munautbc9f5c42020-09-14 10:22:29 +020018
Harald Welte069d3432020-12-15 23:09:40 +010019#include "ice1usb_proto.h"
20
Sylvain Munautbc9f5c42020-09-14 10:22:29 +020021struct {
Harald Welte37701e92020-12-14 15:56:28 +010022 bool running; /* are we running (transceiving USB data)? */
23 int out_bdi; /* buffer descriptor index for OUT EP */
24 int in_bdi; /* buffer descriptor index for IN EP */
Harald Welte069d3432020-12-15 23:09:40 +010025 struct ice1usb_tx_config tx_cfg;
26 struct ice1usb_rx_config rx_cfg;
27} g_usb_e1 = {
28 /* default configuration at power-up */
29 .tx_cfg = {
30 .mode = ICE1USB_TX_MODE_TS0_CRC4_E,
31 .timing = ICE1USB_TX_TIME_SRC_REMOTE,
32 .ext_loopback = ICE1USB_TX_EXT_LOOPBACK_OFF,
33 .alarm = 0,
34 },
35 .rx_cfg = {
36 .mode = ICE1USB_RX_MODE_MULTIFRAME,
37 },
38};
Sylvain Munautbc9f5c42020-09-14 10:22:29 +020039
40
41/* Hack */
Harald Welteb7aced62020-12-14 17:39:23 +010042unsigned int e1_rx_need_data(unsigned int usb_addr, unsigned int max_len, unsigned int *pos);
Sylvain Munautbc9f5c42020-09-14 10:22:29 +020043unsigned int e1_tx_feed_data(unsigned int usb_addr, unsigned int len);
44unsigned int e1_tx_level(void);
45unsigned int e1_rx_level(void);
46/* ---- */
47
48bool
49usb_ep_boot(const struct usb_intf_desc *intf, uint8_t ep_addr, bool dual_bd);
50
51static 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) */
Harald Welte6603e1f2020-12-15 18:38:37 +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 */
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
88 /* EP2 IN */
89 bdi = g_usb_e1.in_bdi;
90
91 while ((usb_ep_regs[2].in.bd[bdi].csr & USB_BD_STATE_MSK) != USB_BD_STATE_RDY_DATA)
92 {
93 uint32_t ptr = usb_ep_regs[2].in.bd[bdi].ptr;
Harald Welte394b6802020-12-14 17:46:53 +010094 uint32_t errmask;
Sylvain Munautbc9f5c42020-09-14 10:22:29 +020095 uint32_t hdr;
Harald Welte394b6802020-12-14 17:46:53 +010096 unsigned int pos;
Sylvain Munautbc9f5c42020-09-14 10:22:29 +020097
98 /* Error check */
99 if ((usb_ep_regs[2].in.bd[bdi].csr & USB_BD_STATE_MSK) == USB_BD_STATE_DONE_ERR)
100 puts("Err EP2 IN\n");
101
102 /* Get some data from E1 */
103 int n = e1_rx_level();
104
105 if (n > 64)
106 n = 12;
107 else if (n > 32)
108 n = 10;
109 else if (n > 8)
110 n = 8;
111 else if (!n)
112 break;
113
Harald Welte394b6802020-12-14 17:46:53 +0100114 n = e1_rx_need_data((ptr >> 2) + 1, n, &pos);
Sylvain Munautbc9f5c42020-09-14 10:22:29 +0200115
116 /* Write header */
Harald Welte394b6802020-12-14 17:46:53 +0100117 errmask = e1_get_and_clear_errors();
118 hdr = (4 << 28) | ((errmask & 0xff) << 8) | (pos & 0xff);
Sylvain Munautbc9f5c42020-09-14 10:22:29 +0200119 usb_data_write(ptr, &hdr, 4);
120
121 /* Resubmit */
122 usb_ep_regs[2].in.bd[bdi].csr = USB_BD_STATE_RDY_DATA | USB_BD_LEN((n * 32) + 4);
123
124 /* Next BDI */
125 bdi ^= 1;
126 g_usb_e1.in_bdi = bdi;
127 }
128
129 /* EP1 OUT */
130 bdi = g_usb_e1.out_bdi;
131
132 while ((usb_ep_regs[1].out.bd[bdi].csr & USB_BD_STATE_MSK) != USB_BD_STATE_RDY_DATA)
133 {
134 uint32_t ptr = usb_ep_regs[1].out.bd[bdi].ptr;
135 uint32_t csr = usb_ep_regs[1].out.bd[bdi].csr;
136 uint32_t hdr;
137
138 /* Error check */
139 if ((csr & USB_BD_STATE_MSK) == USB_BD_STATE_DONE_ERR) {
140 puts("Err EP1 OUT\n");
141 goto refill;
142 }
143
144 /* Grab header */
145 usb_data_read(&hdr, ptr, 4);
146
147 /* Empty data into the FIFO */
148 int n = ((csr & USB_BD_LEN_MSK) - 4) / 32;
149 n = e1_tx_feed_data((ptr >> 2) + 1, n);
150
151refill:
152 /* Refill it */
153 usb_ep_regs[1].out.bd[bdi].csr = USB_BD_STATE_RDY_DATA | USB_BD_LEN(388);
154
155 /* Next BDI */
156 bdi ^= 1;
157 g_usb_e1.out_bdi = bdi;
158
159 static int x = 0;
160 if ((x++ & 0xff) == 0xff)
161 puts(".");
162 }
163
164 /* EP1 IN */
165 if ((usb_ep_regs[1].in.bd[0].csr & USB_BD_STATE_MSK) != USB_BD_STATE_RDY_DATA)
166 {
167 _usb_fill_feedback_ep();
168 }
169}
170
171static const struct usb_intf_desc *
172_find_intf(const struct usb_conf_desc *conf, uint8_t idx)
173{
174 const struct usb_intf_desc *intf = NULL;
175 const void *sod, *eod;
176
177 if (!conf)
178 return NULL;
179
180 sod = conf;
181 eod = sod + conf->wTotalLength;
182
183 while (1) {
184 sod = usb_desc_find(sod, eod, USB_DT_INTF);
185 if (!sod)
186 break;
187
188 intf = (void*)sod;
189 if (intf->bInterfaceNumber == idx)
190 return intf;
191
192 sod = usb_desc_next(sod);
193 }
194
195 return NULL;
196}
Harald Weltec8271852020-12-14 13:48:09 +0100197
198static 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
207 intf = _find_intf(conf, 0);
208 if (!intf)
209 return USB_FND_ERROR;
210
211 printf("e1 set_conf %08x\n", intf);
212
213 usb_ep_boot(intf, 0x01, true);
214 usb_ep_boot(intf, 0x81, true);
215 usb_ep_boot(intf, 0x82, true);
Harald Welte22bcd182020-12-15 08:47:26 +0100216 usb_ep_boot(intf, 0x83, true);
Sylvain Munautbc9f5c42020-09-14 10:22:29 +0200217
218 return USB_FND_SUCCESS;
219}
220
Harald Weltec8271852020-12-14 13:48:09 +0100221static enum usb_fnd_resp
Sylvain Munautbc9f5c42020-09-14 10:22:29 +0200222_e1_set_intf(const struct usb_intf_desc *base, const struct usb_intf_desc *sel)
223{
224 if (base->bInterfaceNumber != 0)
225 return USB_FND_CONTINUE;
226
227 if (sel->bAlternateSetting != 1)
228 return USB_FND_SUCCESS;
229
230 /* Hack to avoid re-setting while running ... avoid BD desync */
231 if (g_usb_e1.running)
232 return USB_FND_SUCCESS;
233
234 g_usb_e1.running = true;
235
236 /* Configure EP1 OUT / EP2 IN */
237 usb_ep_regs[1].out.status = USB_EP_TYPE_ISOC | USB_EP_BD_DUAL; /* Type=Isochronous, dual buffered */
238 usb_ep_regs[2].in.status = USB_EP_TYPE_ISOC | USB_EP_BD_DUAL; /* Type=Isochronous, dual buffered */
239
240 /* Configure EP1 IN (feedback) */
241 usb_ep_regs[1].in.status = USB_EP_TYPE_ISOC; /* Type=Isochronous, single buffered */
242
243 /* EP2 IN: Prepare two buffers */
244 usb_ep_regs[2].in.bd[0].ptr = 1024;
245 usb_ep_regs[2].in.bd[0].csr = 0;
246
247 usb_ep_regs[2].in.bd[1].ptr = 1536;
248 usb_ep_regs[2].in.bd[1].csr = 0;
249
250 /* EP1 OUT: Queue two buffers */
251 usb_ep_regs[1].out.bd[0].ptr = 1024;
252 usb_ep_regs[1].out.bd[0].csr = USB_BD_STATE_RDY_DATA | USB_BD_LEN(388);
253
254 usb_ep_regs[1].out.bd[1].ptr = 1536;
255 usb_ep_regs[1].out.bd[1].csr = USB_BD_STATE_RDY_DATA | USB_BD_LEN(388);
256
257 /* EP1 IN: Queue buffer */
258 _usb_fill_feedback_ep();
259
Harald Welte22bcd182020-12-15 08:47:26 +0100260 /* EP3 IN: Interrupt */
261 usb_ep_regs[3].in.status = USB_EP_TYPE_INT;
262 usb_ep_regs[3].in.bd[0].ptr = 0;
263 usb_ep_regs[3].in.bd[0].csr = 0;
264
Sylvain Munautbc9f5c42020-09-14 10:22:29 +0200265 return USB_FND_SUCCESS;
266}
267
Harald Weltec8271852020-12-14 13:48:09 +0100268static enum usb_fnd_resp
Sylvain Munautbc9f5c42020-09-14 10:22:29 +0200269_e1_get_intf(const struct usb_intf_desc *base, uint8_t *alt)
270{
271 if (base->bInterfaceNumber != 0)
272 return USB_FND_CONTINUE;
273
274 *alt = g_usb_e1.running ? 1 : 0;
275
276 return USB_FND_SUCCESS;
277}
278
Harald Welte069d3432020-12-15 23:09:40 +0100279static bool
280_set_tx_mode_done(struct usb_xfer *xfer)
281{
282 const struct ice1usb_tx_config *cfg = (const struct ice1usb_tx_config *) xfer->data;
283 printf("set_tx_mode %02x%02x%02x%02x\r\n",
284 xfer->data[0], xfer->data[1], xfer->data[2], xfer->data[3]);
285 g_usb_e1.tx_cfg = *cfg;
286 /* FIXME: actually change E1 core config */
287 return true;
288}
289
290static bool
291_set_rx_mode_done(struct usb_xfer *xfer)
292{
293 const struct ice1usb_rx_config *cfg = (const struct ice1usb_rx_config *) xfer->data;
294 printf("set_rx_mode %02x\r\n", xfer->data[0]);
295 g_usb_e1.rx_cfg = *cfg;
296 /* FIXME: actually change E1 core config */
297 return true;
298}
299
300/* per-interface requests */
301static enum usb_fnd_resp
302_e1_ctrl_req_intf(struct usb_ctrl_req *req, struct usb_xfer *xfer)
303{
304 unsigned int i;
305
306 switch (req->bRequest) {
307 case ICE1USB_INTF_GET_CAPABILITIES:
308 /* no optional capabilities yet */
309 xfer->len = 0;
310 break;
311 case ICE1USB_INTF_SET_TX_CFG:
312 if (req->wLength < sizeof(struct ice1usb_tx_config))
313 return USB_FND_ERROR;
314 xfer->cb_done = _set_tx_mode_done;
315 xfer->cb_ctx = req;
316 xfer->len = sizeof(struct ice1usb_tx_config);
317 break;
318 case ICE1USB_INTF_GET_TX_CFG:
319 if (req->wLength < sizeof(struct ice1usb_tx_config))
320 return USB_FND_ERROR;
321 memcpy(xfer->data, &g_usb_e1.tx_cfg, sizeof(struct ice1usb_tx_config));
322 xfer->len = sizeof(struct ice1usb_tx_config);
323 break;
324 case ICE1USB_INTF_SET_RX_CFG:
325 if (req->wLength < sizeof(struct ice1usb_rx_config))
326 return USB_FND_ERROR;
327 xfer->cb_done = _set_rx_mode_done;
328 xfer->cb_ctx = req;
329 xfer->len = sizeof(struct ice1usb_rx_config);
330 break;
331 case ICE1USB_INTF_GET_RX_CFG:
332 if (req->wLength < sizeof(struct ice1usb_rx_config))
333 return USB_FND_ERROR;
334 memcpy(xfer->data, &g_usb_e1.rx_cfg, sizeof(struct ice1usb_rx_config));
335 xfer->len = sizeof(struct ice1usb_rx_config);
336 break;
337 default:
338 return USB_FND_ERROR;
339 }
340
341 return USB_FND_SUCCESS;
342}
343
344/* device-global requests */
345static enum usb_fnd_resp
346_e1_ctrl_req_dev(struct usb_ctrl_req *req, struct usb_xfer *xfer)
347{
348 switch (req->bRequest) {
349 case ICE1USB_DEV_GET_CAPABILITIES:
350 xfer->data[0] = (1 << ICE1USB_DEV_CAP_GPSDO);
351 xfer->len = 1;
352 break;
353 default:
354 return USB_FND_ERROR;
355 }
356
357 return USB_FND_SUCCESS;
358}
359
360
361/* USB host issues a control request to us */
362static enum usb_fnd_resp
363_e1_ctrl_req(struct usb_ctrl_req *req, struct usb_xfer *xfer)
364{
365 if (USB_REQ_TYPE(req) != USB_REQ_TYPE_VENDOR)
366 return USB_FND_CONTINUE;
367
368 switch (USB_REQ_RCPT(req)) {
369 case USB_REQ_RCPT_DEV:
370 return _e1_ctrl_req_dev(req, xfer);
371 case USB_REQ_RCPT_INTF:
372 if (req->wIndex != 0)
373 return USB_FND_ERROR;
374 return _e1_ctrl_req_intf(req, xfer);
375 case USB_REQ_RCPT_EP:
376 case USB_REQ_RCPT_OTHER:
377 default:
378 return USB_FND_ERROR;
379 }
380}
381
382
Sylvain Munautbc9f5c42020-09-14 10:22:29 +0200383static struct usb_fn_drv _e1_drv = {
384 .set_conf = _e1_set_conf,
385 .set_intf = _e1_set_intf,
386 .get_intf = _e1_get_intf,
Harald Welte069d3432020-12-15 23:09:40 +0100387 .ctrl_req = _e1_ctrl_req,
Sylvain Munautbc9f5c42020-09-14 10:22:29 +0200388};
389
390void
391usb_e1_init(void)
392{
393 memset(&g_usb_e1, 0x00, sizeof(g_usb_e1));
394 usb_register_function_driver(&_e1_drv);
395}