blob: dc2ae11c2a2ed2e3548f7f00d18ab574a4be38ef [file] [log] [blame]
Sylvain Munautf5d7bf22020-09-14 10:23:50 +02001/*
2 * 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.h>
13
14#include "config.h"
15#include "console.h"
16#include "e1.h"
17
18#include "dma.h"
19#include "led.h" // FIXME
20
21
22// Hardware
23// --------
24
25struct e1_chan {
26 uint32_t csr;
27 uint32_t bd;
28 uint32_t _rsvd[2];
29} __attribute__((packed,aligned(4)));
30
31struct e1_core {
32 struct e1_chan rx[2];
33} __attribute__((packed,aligned(4)));
34
35#define E1_RX_CR_ENABLE (1 << 0)
36#define E1_RX_CR_MODE_TRSP (0 << 1)
37#define E1_RX_CR_MODE_BYTE (1 << 1)
38#define E1_RX_CR_MODE_BFA (2 << 1)
39#define E1_RX_CR_MODE_MFA (3 << 1)
40#define E1_RX_CR_OVFL_CLR (1 << 12)
41#define E1_RX_SR_ENABLED (1 << 0)
42#define E1_RX_SR_ALIGNED (1 << 1)
43#define E1_RX_SR_BD_IN_EMPTY (1 << 8)
44#define E1_RX_SR_BD_IN_FULL (1 << 9)
45#define E1_RX_SR_BD_OUT_EMPTY (1 << 10)
46#define E1_RX_SR_BD_OUT_FULL (1 << 11)
47#define E1_RX_SR_OVFL (1 << 12)
48
49#define E1_BD_VALID (1 << 15)
50#define E1_BD_CRC1 (1 << 14)
51#define E1_BD_CRC0 (1 << 13)
52#define E1_BD_ADDR(x) ((x) & 0x7f)
53#define E1_BD_ADDR_MSK 0x7f
54#define E1_BD_ADDR_SHFT 0
55
56
57static volatile struct e1_core * const e1_regs = (void *)(E1_CORE_BASE);
58static volatile uint8_t * const e1_data = (void *)(E1_DATA_BASE);
59
60
61volatile uint8_t *
62e1_data_ptr(int mf, int frame, int ts)
63{
64 return &e1_data[(mf << 9) | (frame << 5) | ts];
65}
66
67unsigned int
68e1_data_ofs(int mf, int frame, int ts)
69{
70 return (mf << 9) | (frame << 5) | ts;
71}
72
73
74// FIFOs
75// -----
76/* Note: FIFO works at 'frame' level (i.e. 32 bytes) */
77
78struct e1_fifo {
79 /* Buffer zone associated with the FIFO */
80 unsigned int base;
81 unsigned int mask;
82
83 /* Pointers / Levels */
84 unsigned int wptr[2]; /* 0=committed 1=allocated */
85 unsigned int rptr[2]; /* 0=discared 1=peeked */
86};
87
88 /* Utils */
89static void
90e1f_reset(struct e1_fifo *fifo, unsigned int base, unsigned int len)
91{
92 memset(fifo, 0x00, sizeof(struct e1_fifo));
93 fifo->base = base;
94 fifo->mask = len - 1;
95}
96
97static unsigned int
98e1f_allocd_frames(struct e1_fifo *fifo)
99{
100 /* Number of frames that are allocated (i.e. where we can't write to) */
101 return (fifo->wptr[1] - fifo->rptr[0]) & fifo->mask;
102}
103
104static unsigned int
105e1f_valid_frames(struct e1_fifo *fifo)
106{
107 /* Number of valid frames */
108 return (fifo->wptr[0] - fifo->rptr[0]) & fifo->mask;
109}
110
111static unsigned int
112e1f_unseen_frames(struct e1_fifo *fifo)
113{
114 /* Number of valid frames that haven't been peeked yet */
115 return (fifo->wptr[0] - fifo->rptr[1]) & fifo->mask;
116}
117
118static unsigned int
119e1f_free_frames(struct e1_fifo *fifo)
120{
121 /* Number of frames that aren't allocated */
122 return (fifo->rptr[0] - fifo->wptr[1] - 1) & fifo->mask;
123}
124
125static unsigned int
126e1f_ofs_to_dma(unsigned int ofs)
127{
128 /* DMA address are 32-bits word address. Offsets are 32 byte address */
129 return (ofs << 3);
130}
131
132static unsigned int
133e1f_ofs_to_mf(unsigned int ofs)
134{
135 /* E1 Buffer Descriptors are always multiframe aligned */
136 return (ofs >> 4);
137}
138
139
140 /* Debug */
141static void
142e1f_debug(struct e1_fifo *fifo, const char *name)
143{
144 unsigned int la, lv, lu, lf;
145
146 la = e1f_allocd_frames(fifo);
147 lv = e1f_valid_frames(fifo);
148 lu = e1f_unseen_frames(fifo);
149 lf = e1f_free_frames(fifo);
150
151 printf("%s: R: %u / %u | W: %u / %u | A:%u V:%u U:%u F:%u\n",
152 name,
153 fifo->rptr[0], fifo->rptr[1], fifo->wptr[0], fifo->wptr[1],
154 la, lv, lu, lf
155 );
156}
157
158 /* Frame level read/write */
159static unsigned int
160e1f_frame_write(struct e1_fifo *fifo, unsigned int *ofs, unsigned int max_frames)
161{
162 unsigned int lf, le;
163
164 lf = e1f_free_frames(fifo);
165 le = fifo->mask - fifo->wptr[0] + 1;
166
167 if (max_frames > le)
168 max_frames = le;
169 if (max_frames > lf)
170 max_frames = lf;
171
172 *ofs = fifo->base + fifo->wptr[0];
173 fifo->wptr[1] = fifo->wptr[0] = (fifo->wptr[0] + max_frames) & fifo->mask;
174
175 return max_frames;
176}
177
178static unsigned int
Sylvain Munautde20fb72020-10-29 13:24:50 +0100179e1f_frame_read(struct e1_fifo *fifo, unsigned int *ofs, unsigned int max_frames)
Sylvain Munautf5d7bf22020-09-14 10:23:50 +0200180{
181 unsigned int lu, le;
182
183 lu = e1f_unseen_frames(fifo);
184 le = fifo->mask - fifo->rptr[1] + 1;
185
186 if (max_frames > le)
187 max_frames = le;
188 if (max_frames > lu)
189 max_frames = lu;
190
191 *ofs = fifo->base + fifo->rptr[1];
192 fifo->rptr[0] = fifo->rptr[1] = (fifo->rptr[1] + max_frames) & fifo->mask;
193
194 return max_frames;
195}
196
197
198 /* MultiFrame level split read/write */
199static bool
200e1f_multiframe_write_prepare(struct e1_fifo *fifo, unsigned int *ofs)
201{
202 unsigned int lf;
203
204 lf = e1f_free_frames(fifo);
205 if (lf < 16)
206 return false;
207
208 *ofs = fifo->base + fifo->wptr[1];
209 fifo->wptr[1] = (fifo->wptr[1] + 16) & fifo->mask;
210
211 return true;
212}
213
214static void
215e1f_multiframe_write_commit(struct e1_fifo *fifo)
216{
217 fifo->wptr[0] = (fifo->wptr[0] + 16) & fifo->mask;
218}
219
220static bool
221e1f_multiframe_read_peek(struct e1_fifo *fifo, unsigned int *ofs)
222{
223 unsigned int lu;
224
225 lu = e1f_unseen_frames(fifo);
226 if (lu < 16)
227 return false;
228
229 *ofs = fifo->base + fifo->rptr[1];
230 fifo->rptr[1] = (fifo->rptr[1] + 16) & fifo->mask;
231
232 return true;
233}
234
235static void
236e1f_multiframe_read_discard(struct e1_fifo *fifo)
237{
238 fifo->rptr[0] = (fifo->rptr[0] + 16) & fifo->mask;
239}
240
241static void
242e1f_multiframe_empty(struct e1_fifo *fifo)
243{
244 fifo->rptr[0] = fifo->rptr[1] = (fifo->wptr[0] & ~15);
245}
246
247
248
249// Main logic
250// ----------
251
252enum e1_pipe_state {
253 IDLE = 0,
254 BOOT = 1,
255 RUN = 2,
256 RECOVER = 3,
257};
258
259static struct {
260 struct {
261 uint32_t cr;
262 struct e1_fifo fifo;
263 short in_flight;
264 enum e1_pipe_state state;
265 uint8_t flags;
266 } rx[2];
267 uint32_t error;
268} g_e1;
269
270
271void
272e1_init(void)
273{
274 /* Global state init */
275 memset(&g_e1, 0x00, sizeof(g_e1));
276}
277
278void
279e1_start(void)
280{
281 /* Reset FIFOs */
282#ifdef BIGBUF
283 e1f_reset(&g_e1.rx[0].fifo, 0, 1024);
284 e1f_reset(&g_e1.rx[1].fifo, 1024, 1024);
285#else
286 e1f_reset(&g_e1.rx[0].fifo, 0, 128);
287 e1f_reset(&g_e1.rx[1].fifo, 128, 128);
288#endif
289
290 /* Enable Rx0 */
291 g_e1.rx[0].cr = E1_RX_CR_OVFL_CLR |
292 E1_RX_CR_MODE_MFA |
293 E1_RX_CR_ENABLE;
294 e1_regs->rx[0].csr = g_e1.rx[0].cr;
295
296 /* Enable Rx1 */
297 g_e1.rx[1].cr = E1_RX_CR_OVFL_CLR |
298 E1_RX_CR_MODE_MFA |
299 E1_RX_CR_ENABLE;
300 e1_regs->rx[1].csr = g_e1.rx[1].cr;
301
302 /* State */
303 g_e1.rx[0].state = BOOT;
304 g_e1.rx[0].in_flight = 0;
305 g_e1.rx[0].flags = 0;
306
307 g_e1.rx[1].state = BOOT;
308 g_e1.rx[1].in_flight = 0;
309 g_e1.rx[1].flags = 0;
310}
311
312void
313e1_stop()
314{
315 /* Disable RX0 */
316 g_e1.rx[0].cr = 0;
317 e1_regs->rx[0].csr = g_e1.rx[0].cr;
318
319 /* Disable RX1 */
320 g_e1.rx[1].cr = 0;
321 e1_regs->rx[1].csr = g_e1.rx[1].cr;
322
323 /* State */
324 g_e1.rx[0].state = IDLE;
325 g_e1.rx[1].state = IDLE;
326}
327
328
329#include "dma.h"
330
331unsigned int
332e1_rx_need_data(int chan, unsigned int usb_addr, unsigned int max_frames, unsigned int *pos)
333{
334 unsigned int ofs;
335 int tot_frames = 0;
336 int n_frames;
337
338 while (max_frames) {
339 /* Get some data from the FIFO */
340 n_frames = e1f_frame_read(&g_e1.rx[chan].fifo, &ofs, max_frames);
341 if (!n_frames)
342 break;
343
344 /* Give pos */
345 if (pos) {
346 *pos = ofs & g_e1.rx[chan].fifo.mask;
347 pos = NULL;
348 }
349
350 /* Copy from FIFO to USB */
351 dma_exec(e1f_ofs_to_dma(ofs), usb_addr, n_frames * (32 / 4), false, NULL, NULL);
352
353 /* Prepare Next */
354 usb_addr += n_frames * (32 / 4);
355 max_frames -= n_frames;
356 tot_frames += n_frames;
357
358 /* Wait for DMA completion */
359 while (dma_poll());
360 }
361
362 return tot_frames;
363}
364
365unsigned int
366e1_rx_level(int chan)
367{
368 return e1f_valid_frames(&g_e1.rx[chan].fifo);
369}
370
371uint8_t
372e1_get_pending_flags(int chan)
373{
374 uint8_t f = g_e1.rx[chan].flags;
375 g_e1.rx[chan].flags = 0;
376 return f;
377}
378
379
380#define ERR_TIME 1000
381
382void
383e1_poll(void)
384{
385 uint32_t bd;
386 unsigned int ofs;
387 int chan;
388 bool error = false;
389
390 /* HACK: LED link status */
391 if ((g_e1.rx[0].state == IDLE) && (g_e1.rx[1].state == IDLE))
392 {
393 /* Static dim red */
394 led_color(32, 0, 0);
395 led_blink(false, 0, 0);
396 } else {
397 uint32_t csr[2];
398
399 csr[0] = e1_regs->rx[0].csr;
400 csr[1] = e1_regs->rx[1].csr;
401
402 if (!((csr[0] & csr[1]) & E1_RX_SR_ALIGNED))
403 error = true;
404
405 /* Color is current SYNC status */
406 led_color(
407 error ? 1 : 0,
408 csr[0] & E1_RX_SR_ALIGNED ? 48 : 0,
409 csr[1] & E1_RX_SR_ALIGNED ? 112 : 0
410 );
411 }
412
413 /* Active ? */
414 if ((g_e1.rx[0].state == IDLE) && (g_e1.rx[1].state == IDLE))
415 return;
416
417 /* Recover any done RX BD */
418 for (chan=0; chan<2; chan++)
419 {
420 while ( (bd = e1_regs->rx[chan].bd) & E1_BD_VALID ) {
421 /* FIXME: CRC status ? */
422 e1f_multiframe_write_commit(&g_e1.rx[chan].fifo);
423 if ((bd & (E1_BD_CRC0 | E1_BD_CRC1)) != (E1_BD_CRC0 | E1_BD_CRC1)) {
424 printf("b: %03x\n", bd);
425 g_e1.rx[chan].flags |= 4;
426 error = true;
427 }
428 g_e1.rx[chan].in_flight--;
429 }
430 }
431
432 /* Handle RX */
433 for (chan=0; chan<2; chan++)
434 {
435 /* Misalign ? */
436 if (g_e1.rx[chan].state == RUN) {
437 if (!(e1_regs->rx[chan].csr & E1_RX_SR_ALIGNED)) {
438 printf("[!] E1 rx misalign\n");
439 g_e1.rx[chan].state = RECOVER;
440 g_e1.rx[chan].flags |= 1;
441 error = true;
442 }
443 }
444
445 /* Overflow ? */
446 if (g_e1.rx[chan].state == RUN) {
447 if (e1_regs->rx[chan].csr & E1_RX_SR_OVFL) {
448 printf("[!] E1 overflow %d\n", g_e1.rx[chan].in_flight);
449 g_e1.rx[chan].state = RECOVER;
450 g_e1.rx[chan].flags |= 2;
451 }
452 }
453
454 /* Recover ready ? */
455 if (g_e1.rx[chan].state == RECOVER) {
456 if (g_e1.rx[chan].in_flight != 0)
457 continue;
458 e1f_multiframe_empty(&g_e1.rx[chan].fifo);
459 }
460
461 /* Fill new RX BD */
462 while (g_e1.rx[chan].in_flight < 4) {
463 if (!e1f_multiframe_write_prepare(&g_e1.rx[chan].fifo, &ofs))
464 break;
465 e1_regs->rx[chan].bd = e1f_ofs_to_mf(ofs);
466 g_e1.rx[chan].in_flight++;
467 }
468
469 /* Clear overflow if needed */
470 if (g_e1.rx[chan].state != RUN) {
471 e1_regs->rx[chan].csr = g_e1.rx[chan].cr | E1_RX_CR_OVFL_CLR;
472 g_e1.rx[chan].state = RUN;
473 }
474 }
475
476 /* Error tracking */
477 if (error) {
478 if (!g_e1.error) {
479 printf("Error LED\n");
480 led_blink(true, 150, 150);
481 }
482 g_e1.error = usb_get_tick() + ERR_TIME;
483 } else if (g_e1.error && (g_e1.error < usb_get_tick())) {
484 g_e1.error = 0;
485 led_blink(false, 0, 0);
486 printf("No error\n");
487 }
488
489}
490
491void
492e1_debug_print(bool data)
493{
494 volatile uint8_t *p;
495
496 puts("E1\n");
497 printf("CSR: Rx0 %04x / Rx1 %04x\n", e1_regs->rx[0].csr, e1_regs->rx[1].csr);
498 printf("InF: Rx0 %d / Rx1 %d\n", g_e1.rx[0].in_flight, g_e1.rx[1].in_flight);
499 printf("Sta: Rx0 %d / Rx1 %d\n", g_e1.rx[0].state, g_e1.rx[1].state);
500
501 e1f_debug(&g_e1.rx[0].fifo, "Rx0 FIFO");
502 e1f_debug(&g_e1.rx[1].fifo, "Rx1 FIFO");
503
504 if (data) {
505 puts("\nE1 Data\n");
506 for (int f=0; f<16; f++) {
507 p = e1_data_ptr(0, f, 0);
508 for (int ts=0; ts<32; ts++)
509 printf(" %02x", p[ts]);
510 printf("\n");
511 }
512 }
513}