blob: 09b428cfefae2b1d9e63da6d1a85b1d62a973267 [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
19#include "ice1usb_proto.h"
Sylvain Munautbc9f5c42020-09-14 10:22:29 +020020
21struct {
Harald Welte30fc5602020-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 Welte9469e042020-12-15 23:09:40 +010025 struct ice1usb_tx_config tx_cfg;
26 struct ice1usb_rx_config rx_cfg;
Harald Welte805f2cf2020-12-14 17:31:03 +010027 struct e1_error_count last_err;
Sylvain Munautbc9f5c42020-09-14 10:22:29 +020028} g_usb_e1;
29
Harald Welte9469e042020-12-15 23:09:40 +010030/* default configuration at power-up */
31static const struct ice1usb_tx_config tx_cfg_default = {
32 .mode = ICE1USB_TX_MODE_TS0_CRC4_E,
33 .timing = ICE1USB_TX_TIME_SRC_LOCAL,
34 .ext_loopback = ICE1USB_TX_EXT_LOOPBACK_OFF,
35 .alarm = 0,
36};
37
38static const struct ice1usb_rx_config rx_cfg_default = {
39 .mode = ICE1USB_RX_MODE_MULTIFRAME,
40};
41
Sylvain Munautbc9f5c42020-09-14 10:22:29 +020042
Sylvain Munautbc9f5c42020-09-14 10:22:29 +020043static void
44_usb_fill_feedback_ep(void)
45{
46 static uint16_t ticks_prev = 0;
47 uint16_t ticks;
48 uint32_t val = 8192;
49 unsigned int level;
50
Harald Welte2b7dadf2020-12-14 15:56:15 +010051 /* Compute real E1 tick count (with safety against bad values) */
Sylvain Munautbc9f5c42020-09-14 10:22:29 +020052 ticks = e1_tick_read();
53 val = (ticks - ticks_prev) & 0xffff;
54 ticks_prev = ticks;
55 if ((val < 7168) | (val > 9216))
56 val = 8192;
57
58 /* Bias depending on TX fifo level */
59 level = e1_tx_level();
60 if (level < (3 * 16))
61 val += 256;
62 else if (level > (8 * 16))
63 val -= 256;
64
65 /* Prepare buffer */
Sylvain Munaut96744362022-01-03 17:03:26 +010066 usb_data_write(usb_ep_regs[1].in.bd[0].ptr, &val, 4);
Sylvain Munautbc9f5c42020-09-14 10:22:29 +020067 usb_ep_regs[1].in.bd[0].csr = USB_BD_STATE_RDY_DATA | USB_BD_LEN(3);
68}
69
70
71void
72usb_e1_run(void)
73{
74 int bdi;
75
76 if (!g_usb_e1.running)
77 return;
78
Harald Welte805f2cf2020-12-14 17:31:03 +010079 /* EP3 IRQ */
80 if ((usb_ep_regs[3].in.bd[0].csr & USB_BD_STATE_MSK) != USB_BD_STATE_RDY_DATA) {
81 const struct e1_error_count *cur_err = e1_get_error_count();
82 if (memcmp(cur_err, &g_usb_e1.last_err, sizeof(*cur_err))) {
83 struct ice1usb_irq errmsg = {
84 .type = ICE1USB_IRQ_T_ERRCNT,
85 .u = {
86 .errors = {
87 .crc = cur_err->crc,
88 .align = cur_err->align,
89 .ovfl = cur_err->ovfl,
90 .unfl = cur_err->unfl,
91 .flags = cur_err->flags,
92 }
93 }
94 };
95 printf("E");
96 usb_data_write(usb_ep_regs[3].in.bd[0].ptr, &errmsg, sizeof(errmsg));
97 usb_ep_regs[3].in.bd[0].csr = USB_BD_STATE_RDY_DATA | USB_BD_LEN(sizeof(errmsg));
98 g_usb_e1.last_err = *cur_err;
99 }
100 }
101
Sylvain Munautbc9f5c42020-09-14 10:22:29 +0200102 /* EP2 IN */
103 bdi = g_usb_e1.in_bdi;
104
105 while ((usb_ep_regs[2].in.bd[bdi].csr & USB_BD_STATE_MSK) != USB_BD_STATE_RDY_DATA)
106 {
107 uint32_t ptr = usb_ep_regs[2].in.bd[bdi].ptr;
108 uint32_t hdr;
Harald Welte2df1f802020-12-14 17:46:53 +0100109 unsigned int pos;
Sylvain Munautbc9f5c42020-09-14 10:22:29 +0200110
111 /* Error check */
112 if ((usb_ep_regs[2].in.bd[bdi].csr & USB_BD_STATE_MSK) == USB_BD_STATE_DONE_ERR)
113 puts("Err EP2 IN\n");
114
115 /* Get some data from E1 */
116 int n = e1_rx_level();
117
118 if (n > 64)
119 n = 12;
120 else if (n > 32)
121 n = 10;
122 else if (n > 8)
123 n = 8;
124 else if (!n)
125 break;
126
Harald Welte2df1f802020-12-14 17:46:53 +0100127 n = e1_rx_need_data((ptr >> 2) + 1, n, &pos);
Sylvain Munautbc9f5c42020-09-14 10:22:29 +0200128
Harald Welte2df1f802020-12-14 17:46:53 +0100129 /* Write header: currently version and pos (mfr/fr number) */
130 hdr = (0 << 28) | (pos & 0xff);
Sylvain Munautbc9f5c42020-09-14 10:22:29 +0200131 usb_data_write(ptr, &hdr, 4);
132
133 /* Resubmit */
134 usb_ep_regs[2].in.bd[bdi].csr = USB_BD_STATE_RDY_DATA | USB_BD_LEN((n * 32) + 4);
135
136 /* Next BDI */
137 bdi ^= 1;
138 g_usb_e1.in_bdi = bdi;
139 }
140
141 /* EP1 OUT */
142 bdi = g_usb_e1.out_bdi;
143
144 while ((usb_ep_regs[1].out.bd[bdi].csr & USB_BD_STATE_MSK) != USB_BD_STATE_RDY_DATA)
145 {
146 uint32_t ptr = usb_ep_regs[1].out.bd[bdi].ptr;
147 uint32_t csr = usb_ep_regs[1].out.bd[bdi].csr;
148 uint32_t hdr;
149
150 /* Error check */
151 if ((csr & USB_BD_STATE_MSK) == USB_BD_STATE_DONE_ERR) {
152 puts("Err EP1 OUT\n");
153 goto refill;
154 }
155
156 /* Grab header */
157 usb_data_read(&hdr, ptr, 4);
158
159 /* Empty data into the FIFO */
160 int n = ((csr & USB_BD_LEN_MSK) - 4) / 32;
161 n = e1_tx_feed_data((ptr >> 2) + 1, n);
162
163refill:
164 /* Refill it */
165 usb_ep_regs[1].out.bd[bdi].csr = USB_BD_STATE_RDY_DATA | USB_BD_LEN(388);
166
167 /* Next BDI */
168 bdi ^= 1;
169 g_usb_e1.out_bdi = bdi;
170
171 static int x = 0;
172 if ((x++ & 0xff) == 0xff)
173 puts(".");
174 }
175
176 /* EP1 IN */
177 if ((usb_ep_regs[1].in.bd[0].csr & USB_BD_STATE_MSK) != USB_BD_STATE_RDY_DATA)
178 {
179 _usb_fill_feedback_ep();
180 }
181}
182
Harald Weltec8271852020-12-14 13:48:09 +0100183static enum usb_fnd_resp
Sylvain Munautbc9f5c42020-09-14 10:22:29 +0200184_e1_set_conf(const struct usb_conf_desc *conf)
185{
186 const struct usb_intf_desc *intf;
187
188 printf("e1 set_conf %08x\n", conf);
189 if (!conf)
190 return USB_FND_SUCCESS;
191
Sylvain Munaut96744362022-01-03 17:03:26 +0100192 intf = usb_desc_find_intf(conf, 0, 0, NULL);
Sylvain Munautbc9f5c42020-09-14 10:22:29 +0200193 if (!intf)
194 return USB_FND_ERROR;
195
196 printf("e1 set_conf %08x\n", intf);
197
198 usb_ep_boot(intf, 0x01, true);
Sylvain Munaut96744362022-01-03 17:03:26 +0100199 usb_ep_boot(intf, 0x81, false);
Sylvain Munautbc9f5c42020-09-14 10:22:29 +0200200 usb_ep_boot(intf, 0x82, true);
Sylvain Munaut96744362022-01-03 17:03:26 +0100201 usb_ep_boot(intf, 0x83, false);
Sylvain Munautbc9f5c42020-09-14 10:22:29 +0200202
203 return USB_FND_SUCCESS;
204}
205
Harald Welte9469e042020-12-15 23:09:40 +0100206static void _perform_tx_config(void)
207{
208 const struct ice1usb_tx_config *cfg = &g_usb_e1.tx_cfg;
209 e1_tx_config( ((cfg->mode & 3) << 1) |
210 ((cfg->timing & 1) << 3) |
211 ((cfg->alarm & 1) << 4) |
212 ((cfg->ext_loopback & 3) << 5) );
213}
214
215static void _perform_rx_config(void)
216{
217 const struct ice1usb_rx_config *cfg = &g_usb_e1.rx_cfg;
218 e1_rx_config((cfg->mode << 1));
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{
Sylvain Munaut96744362022-01-03 17:03:26 +0100224 /* Validity checks */
Sylvain Munautbc9f5c42020-09-14 10:22:29 +0200225 if (base->bInterfaceNumber != 0)
226 return USB_FND_CONTINUE;
227
Sylvain Munaut96744362022-01-03 17:03:26 +0100228 if (sel->bAlternateSetting > 1)
229 return USB_FND_ERROR;
Sylvain Munautbc9f5c42020-09-14 10:22:29 +0200230
Sylvain Munaut96744362022-01-03 17:03:26 +0100231 /* Don't do anything if no change */
232 if (g_usb_e1.running == (sel->bAlternateSetting != 0))
233 return USB_FND_SUCCESS;
234
235 g_usb_e1.running = (sel->bAlternateSetting != 0);
236
237 /* Reconfigure the endpoints */
238 usb_ep_reconf(sel, 0x01);
239 usb_ep_reconf(sel, 0x81);
240 usb_ep_reconf(sel, 0x82);
241 usb_ep_reconf(sel, 0x83);
242
243 /* Update E1 and USB state */
244 switch (g_usb_e1.running) {
245 case false:
246 /* Disable E1 rx/tx */
Harald Weltee6b0fe82020-12-17 22:22:05 +0100247 e1_init(0, 0);
Harald Weltee6b0fe82020-12-17 22:22:05 +0100248 break;
Sylvain Munautbc9f5c42020-09-14 10:22:29 +0200249
Sylvain Munaut96744362022-01-03 17:03:26 +0100250 case true:
251 /* Reset and Re-Enable E1 */
252 e1_init(0, 0);
Harald Weltee6b0fe82020-12-17 22:22:05 +0100253 _perform_rx_config();
254 _perform_tx_config();
Sylvain Munautbc9f5c42020-09-14 10:22:29 +0200255
Sylvain Munaut96744362022-01-03 17:03:26 +0100256 /* Reset BDI */
Harald Weltee6b0fe82020-12-17 22:22:05 +0100257 g_usb_e1.in_bdi = 0;
Sylvain Munaut96744362022-01-03 17:03:26 +0100258 g_usb_e1.out_bdi = 0;
Harald Weltee6b0fe82020-12-17 22:22:05 +0100259
260 /* EP1 OUT: Queue two buffers */
Harald Weltee6b0fe82020-12-17 22:22:05 +0100261 usb_ep_regs[1].out.bd[0].csr = USB_BD_STATE_RDY_DATA | USB_BD_LEN(388);
Harald Weltee6b0fe82020-12-17 22:22:05 +0100262 usb_ep_regs[1].out.bd[1].csr = USB_BD_STATE_RDY_DATA | USB_BD_LEN(388);
263
264 /* EP1 IN: Queue buffer */
265 _usb_fill_feedback_ep();
266
Harald Weltee6b0fe82020-12-17 22:22:05 +0100267 break;
Harald Weltee6b0fe82020-12-17 22:22:05 +0100268 }
Harald Welte805f2cf2020-12-14 17:31:03 +0100269
Sylvain Munautbc9f5c42020-09-14 10:22:29 +0200270 return USB_FND_SUCCESS;
271}
272
Harald Weltec8271852020-12-14 13:48:09 +0100273static enum usb_fnd_resp
Sylvain Munautbc9f5c42020-09-14 10:22:29 +0200274_e1_get_intf(const struct usb_intf_desc *base, uint8_t *alt)
275{
276 if (base->bInterfaceNumber != 0)
277 return USB_FND_CONTINUE;
278
279 *alt = g_usb_e1.running ? 1 : 0;
280
281 return USB_FND_SUCCESS;
282}
283
Harald Welte9469e042020-12-15 23:09:40 +0100284static bool
285_set_tx_mode_done(struct usb_xfer *xfer)
286{
287 const struct ice1usb_tx_config *cfg = (const struct ice1usb_tx_config *) xfer->data;
288 printf("set_tx_mode %02x%02x%02x%02x\r\n",
289 xfer->data[0], xfer->data[1], xfer->data[2], xfer->data[3]);
290 g_usb_e1.tx_cfg = *cfg;
291 _perform_tx_config();
292 return true;
293}
294
295static bool
296_set_rx_mode_done(struct usb_xfer *xfer)
297{
298 const struct ice1usb_rx_config *cfg = (const struct ice1usb_rx_config *) xfer->data;
299 printf("set_rx_mode %02x\r\n", xfer->data[0]);
300 g_usb_e1.rx_cfg = *cfg;
301 _perform_rx_config();
302 return true;
303}
304
305/* per-interface requests */
306static enum usb_fnd_resp
307_e1_ctrl_req_intf(struct usb_ctrl_req *req, struct usb_xfer *xfer)
308{
309 unsigned int i;
310
311 switch (req->bRequest) {
312 case ICE1USB_INTF_GET_CAPABILITIES:
313 /* no optional capabilities yet */
314 xfer->len = 0;
315 break;
316 case ICE1USB_INTF_SET_TX_CFG:
317 if (req->wLength < sizeof(struct ice1usb_tx_config))
318 return USB_FND_ERROR;
319 xfer->cb_done = _set_tx_mode_done;
320 xfer->cb_ctx = req;
321 xfer->len = sizeof(struct ice1usb_tx_config);
322 break;
323 case ICE1USB_INTF_GET_TX_CFG:
324 if (req->wLength < sizeof(struct ice1usb_tx_config))
325 return USB_FND_ERROR;
326 memcpy(xfer->data, &g_usb_e1.tx_cfg, sizeof(struct ice1usb_tx_config));
327 xfer->len = sizeof(struct ice1usb_tx_config);
328 break;
329 case ICE1USB_INTF_SET_RX_CFG:
330 if (req->wLength < sizeof(struct ice1usb_rx_config))
331 return USB_FND_ERROR;
332 xfer->cb_done = _set_rx_mode_done;
333 xfer->cb_ctx = req;
334 xfer->len = sizeof(struct ice1usb_rx_config);
335 break;
336 case ICE1USB_INTF_GET_RX_CFG:
337 if (req->wLength < sizeof(struct ice1usb_rx_config))
338 return USB_FND_ERROR;
339 memcpy(xfer->data, &g_usb_e1.rx_cfg, sizeof(struct ice1usb_rx_config));
340 xfer->len = sizeof(struct ice1usb_rx_config);
341 break;
342 default:
343 return USB_FND_ERROR;
344 }
345
346 return USB_FND_SUCCESS;
347}
348
349/* device-global requests */
350static enum usb_fnd_resp
351_e1_ctrl_req_dev(struct usb_ctrl_req *req, struct usb_xfer *xfer)
352{
353 switch (req->bRequest) {
354 case ICE1USB_DEV_GET_CAPABILITIES:
355 xfer->data[0] = (1 << ICE1USB_DEV_CAP_GPSDO);
356 xfer->len = 1;
357 break;
358 default:
359 return USB_FND_ERROR;
360 }
361
362 return USB_FND_SUCCESS;
363}
364
365
366/* USB host issues a control request to us */
367static enum usb_fnd_resp
368_e1_ctrl_req(struct usb_ctrl_req *req, struct usb_xfer *xfer)
369{
370 if (USB_REQ_TYPE(req) != USB_REQ_TYPE_VENDOR)
371 return USB_FND_CONTINUE;
372
373 switch (USB_REQ_RCPT(req)) {
374 case USB_REQ_RCPT_DEV:
375 return _e1_ctrl_req_dev(req, xfer);
376 case USB_REQ_RCPT_INTF:
377 if (req->wIndex != 0)
Sylvain Munaut0f40ee02022-01-03 20:33:08 +0100378 return USB_FND_CONTINUE;
Harald Welte9469e042020-12-15 23:09:40 +0100379 return _e1_ctrl_req_intf(req, xfer);
380 case USB_REQ_RCPT_EP:
381 case USB_REQ_RCPT_OTHER:
382 default:
383 return USB_FND_ERROR;
384 }
385}
386
387
Sylvain Munautbc9f5c42020-09-14 10:22:29 +0200388static struct usb_fn_drv _e1_drv = {
389 .set_conf = _e1_set_conf,
390 .set_intf = _e1_set_intf,
391 .get_intf = _e1_get_intf,
Harald Welte9469e042020-12-15 23:09:40 +0100392 .ctrl_req = _e1_ctrl_req,
Sylvain Munautbc9f5c42020-09-14 10:22:29 +0200393};
394
395void
396usb_e1_init(void)
397{
398 memset(&g_usb_e1, 0x00, sizeof(g_usb_e1));
Harald Welte9469e042020-12-15 23:09:40 +0100399 g_usb_e1.tx_cfg = tx_cfg_default;
400 g_usb_e1.rx_cfg = rx_cfg_default;
Sylvain Munautbc9f5c42020-09-14 10:22:29 +0200401 usb_register_function_driver(&_e1_drv);
402}