blob: 6a4c73cc13a71592f907573c5b058962a2abdc31 [file] [log] [blame]
Sylvain Munautbc9f5c42020-09-14 10:22:29 +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 "config.h"
13#include "console.h"
14#include "e1.h"
Harald Weltef74dad72020-12-15 23:32:53 +010015#include "e1_hw.h"
Sylvain Munautbc9f5c42020-09-14 10:22:29 +020016
17#include "dma.h"
18#include "led.h" // FIXME
19
20
Sylvain Munaut2c0c1362022-01-03 18:48:08 +010021// HW access
22// ---------
23
Sylvain Munautbc9f5c42020-09-14 10:22:29 +020024static volatile struct e1_core * const e1_regs = (void *)(E1_CORE_BASE);
25static volatile uint8_t * const e1_data = (void *)(E1_DATA_BASE);
26
Sylvain Munaut2c0c1362022-01-03 18:48:08 +010027
28// Helpers
29// -------
30
Sylvain Munaut35856a12022-01-03 18:45:53 +010031static unsigned int
Sylvain Munautbc9f5c42020-09-14 10:22:29 +020032e1_data_ofs(int mf, int frame, int ts)
33{
34 return (mf << 9) | (frame << 5) | ts;
35}
36
Sylvain Munaut35856a12022-01-03 18:45:53 +010037static volatile uint8_t *
Harald Weltea59ef2b2020-12-14 17:02:13 +010038e1_data_ptr(int mf, int frame, int ts)
39{
40 return &e1_data[e1_data_ofs(mf, frame, ts)];
41}
Sylvain Munautbc9f5c42020-09-14 10:22:29 +020042
Sylvain Munaut2c0c1362022-01-03 18:48:08 +010043
Sylvain Munautbc9f5c42020-09-14 10:22:29 +020044// FIFOs
45// -----
46/* Note: FIFO works at 'frame' level (i.e. 32 bytes) */
47
48struct e1_fifo {
49 /* Buffer zone associated with the FIFO */
50 unsigned int base;
51 unsigned int mask;
52
53 /* Pointers / Levels */
54 unsigned int wptr[2]; /* 0=committed 1=allocated */
55 unsigned int rptr[2]; /* 0=discared 1=peeked */
56};
57
58 /* Utils */
59static void
60e1f_reset(struct e1_fifo *fifo, unsigned int base, unsigned int len)
61{
62 memset(fifo, 0x00, sizeof(struct e1_fifo));
63 fifo->base = base;
64 fifo->mask = len - 1;
65}
66
67static unsigned int
68e1f_allocd_frames(struct e1_fifo *fifo)
69{
70 /* Number of frames that are allocated (i.e. where we can't write to) */
71 return (fifo->wptr[1] - fifo->rptr[0]) & fifo->mask;
72}
73
74static unsigned int
75e1f_valid_frames(struct e1_fifo *fifo)
76{
77 /* Number of valid frames */
78 return (fifo->wptr[0] - fifo->rptr[0]) & fifo->mask;
79}
80
81static unsigned int
82e1f_unseen_frames(struct e1_fifo *fifo)
83{
84 /* Number of valid frames that haven't been peeked yet */
85 return (fifo->wptr[0] - fifo->rptr[1]) & fifo->mask;
86}
87
88static unsigned int
89e1f_free_frames(struct e1_fifo *fifo)
90{
91 /* Number of frames that aren't allocated */
92 return (fifo->rptr[0] - fifo->wptr[1] - 1) & fifo->mask;
93}
94
95static unsigned int
96e1f_ofs_to_dma(unsigned int ofs)
97{
98 /* DMA address are 32-bits word address. Offsets are 32 byte address */
99 return (ofs << 3);
100}
101
102static unsigned int
103e1f_ofs_to_mf(unsigned int ofs)
104{
105 /* E1 Buffer Descriptors are always multiframe aligned */
106 return (ofs >> 4);
107}
108
Sylvain Munautbc9f5c42020-09-14 10:22:29 +0200109 /* Debug */
110static void
111e1f_debug(struct e1_fifo *fifo, const char *name)
112{
113 unsigned int la, lv, lu, lf;
114
115 la = e1f_allocd_frames(fifo);
116 lv = e1f_valid_frames(fifo);
117 lu = e1f_unseen_frames(fifo);
118 lf = e1f_free_frames(fifo);
119
120 printf("%s: R: %u / %u | W: %u / %u | A:%u V:%u U:%u F:%u\n",
121 name,
122 fifo->rptr[0], fifo->rptr[1], fifo->wptr[0], fifo->wptr[1],
123 la, lv, lu, lf
124 );
125}
126
127 /* Frame level read/write */
128static unsigned int
129e1f_frame_write(struct e1_fifo *fifo, unsigned int *ofs, unsigned int max_frames)
130{
131 unsigned int lf, le;
132
133 lf = e1f_free_frames(fifo);
134 le = fifo->mask - fifo->wptr[0] + 1;
135
136 if (max_frames > le)
137 max_frames = le;
138 if (max_frames > lf)
139 max_frames = lf;
140
141 *ofs = fifo->base + fifo->wptr[0];
142 fifo->wptr[1] = fifo->wptr[0] = (fifo->wptr[0] + max_frames) & fifo->mask;
143
144 return max_frames;
145}
146
147static unsigned int
Sylvain Munautde20fb72020-10-29 13:24:50 +0100148e1f_frame_read(struct e1_fifo *fifo, unsigned int *ofs, unsigned int max_frames)
Sylvain Munautbc9f5c42020-09-14 10:22:29 +0200149{
150 unsigned int lu, le;
151
152 lu = e1f_unseen_frames(fifo);
153 le = fifo->mask - fifo->rptr[1] + 1;
154
155 if (max_frames > le)
156 max_frames = le;
157 if (max_frames > lu)
158 max_frames = lu;
159
160 *ofs = fifo->base + fifo->rptr[1];
161 fifo->rptr[0] = fifo->rptr[1] = (fifo->rptr[1] + max_frames) & fifo->mask;
162
163 return max_frames;
164}
165
166
167 /* MultiFrame level split read/write */
168static bool
169e1f_multiframe_write_prepare(struct e1_fifo *fifo, unsigned int *ofs)
170{
171 unsigned int lf;
172
173 lf = e1f_free_frames(fifo);
174 if (lf < 16)
175 return false;
176
177 *ofs = fifo->base + fifo->wptr[1];
178 fifo->wptr[1] = (fifo->wptr[1] + 16) & fifo->mask;
179
180 return true;
181}
182
183static void
184e1f_multiframe_write_commit(struct e1_fifo *fifo)
185{
186 fifo->wptr[0] = (fifo->wptr[0] + 16) & fifo->mask;
187}
188
189static bool
190e1f_multiframe_read_peek(struct e1_fifo *fifo, unsigned int *ofs)
191{
192 unsigned int lu;
193
194 lu = e1f_unseen_frames(fifo);
195 if (lu < 16)
196 return false;
197
198 *ofs = fifo->base + fifo->rptr[1];
199 fifo->rptr[1] = (fifo->rptr[1] + 16) & fifo->mask;
200
201 return true;
202}
203
204static void
205e1f_multiframe_read_discard(struct e1_fifo *fifo)
206{
207 fifo->rptr[0] = (fifo->rptr[0] + 16) & fifo->mask;
208}
209
210static void
211e1f_multiframe_empty(struct e1_fifo *fifo)
212{
213 fifo->rptr[0] = fifo->rptr[1] = (fifo->wptr[0] & ~15);
214}
215
216
Sylvain Munautbc9f5c42020-09-14 10:22:29 +0200217// Main logic
218// ----------
219
220enum e1_pipe_state {
Harald Welte30fc5602020-12-14 15:56:28 +0100221 IDLE = 0, /* not yet initialized */
222 BOOT = 1, /* after e1_init(), regiters are programmed */
223 RUN = 2, /* normal operation */
224 RECOVER = 3, /* after underflow, overflow or alignment error */
Sylvain Munautbc9f5c42020-09-14 10:22:29 +0200225};
226
227static struct {
228 struct {
229 uint32_t cr;
230 struct e1_fifo fifo;
231 int in_flight;
232 enum e1_pipe_state state;
233 } rx;
234
235 struct {
236 uint32_t cr;
237 struct e1_fifo fifo;
238 int in_flight;
239 enum e1_pipe_state state;
240 } tx;
Sylvain Munaut2c0c1362022-01-03 18:48:08 +0100241
Harald Welte805f2cf2020-12-14 17:31:03 +0100242 struct e1_error_count errors;
Sylvain Munautbc9f5c42020-09-14 10:22:29 +0200243} g_e1;
244
245
Sylvain Munautbc9f5c42020-09-14 10:22:29 +0200246void
Harald Welte9469e042020-12-15 23:09:40 +0100247e1_init(uint16_t rx_cr, uint16_t tx_cr)
Sylvain Munautbc9f5c42020-09-14 10:22:29 +0200248{
249 /* Global state init */
250 memset(&g_e1, 0x00, sizeof(g_e1));
251
252 /* Reset FIFOs */
253 e1f_reset(&g_e1.rx.fifo, 0, 128);
254 e1f_reset(&g_e1.tx.fifo, 128, 128);
255
256 /* Enable Rx */
Harald Welte9469e042020-12-15 23:09:40 +0100257 g_e1.rx.cr = E1_RX_CR_ENABLE | rx_cr;
Harald Welte7f74fe62020-12-27 14:33:37 +0100258 e1_regs->rx.csr = E1_RX_CR_OVFL_CLR | g_e1.rx.cr;
Sylvain Munautbc9f5c42020-09-14 10:22:29 +0200259
260 /* Enable Tx */
Harald Welte9469e042020-12-15 23:09:40 +0100261 g_e1.tx.cr = E1_TX_CR_ENABLE | tx_cr;
Harald Welte7f74fe62020-12-27 14:33:37 +0100262 e1_regs->tx.csr = E1_TX_CR_UNFL_CLR | g_e1.tx.cr;
Sylvain Munautbc9f5c42020-09-14 10:22:29 +0200263
264 /* State */
265 g_e1.rx.state = BOOT;
266 g_e1.tx.state = BOOT;
267}
268
Harald Welte6add0aa2020-12-16 00:02:11 +0100269#define TXCR_PERMITTED ( \
270 E1_TX_CR_MODE_TS0_CRC_E | \
271 E1_TX_CR_TICK_REMOTE | \
272 E1_TX_CR_ALARM | \
273 E1_TX_CR_LOOPBACK | \
274 E1_TX_CR_LOOPBACK_CROSS )
275
276void
277e1_tx_config(uint16_t cr)
278{
279 g_e1.tx.cr = (g_e1.tx.cr & ~TXCR_PERMITTED) | (cr & TXCR_PERMITTED);
280 e1_regs->tx.csr = g_e1.tx.cr;
281}
282
283#define RXCR_PERMITTED ( \
284 E1_RX_CR_MODE_MFA )
285
286void
287e1_rx_config(uint16_t cr)
288{
289 g_e1.rx.cr = (g_e1.rx.cr & ~RXCR_PERMITTED) | (cr & RXCR_PERMITTED);
290 e1_regs->rx.csr = g_e1.rx.cr;
291}
Sylvain Munautbc9f5c42020-09-14 10:22:29 +0200292
Sylvain Munautbc9f5c42020-09-14 10:22:29 +0200293unsigned int
Harald Weltedaff4f62020-12-14 17:39:23 +0100294e1_rx_need_data(unsigned int usb_addr, unsigned int max_frames, unsigned int *pos)
Sylvain Munautbc9f5c42020-09-14 10:22:29 +0200295{
Harald Welte51baa362022-01-01 15:22:25 +0100296 bool rai_received = false;
297 bool rai_possible = false;
Sylvain Munautbc9f5c42020-09-14 10:22:29 +0200298 unsigned int ofs;
299 int tot_frames = 0;
Harald Welte51baa362022-01-01 15:22:25 +0100300 int n_frames, i;
Sylvain Munautbc9f5c42020-09-14 10:22:29 +0200301
302 while (max_frames) {
303 /* Get some data from the FIFO */
304 n_frames = e1f_frame_read(&g_e1.rx.fifo, &ofs, max_frames);
305 if (!n_frames)
306 break;
307
Harald Weltedaff4f62020-12-14 17:39:23 +0100308 /* Give pos */
309 if (pos) {
310 *pos = ofs & g_e1.rx.fifo.mask;
311 pos = NULL;
312 }
313
Sylvain Munautbc9f5c42020-09-14 10:22:29 +0200314 /* Copy from FIFO to USB */
315 dma_exec(e1f_ofs_to_dma(ofs), usb_addr, n_frames * (32 / 4), false, NULL, NULL);
316
317 /* Prepare Next */
318 usb_addr += n_frames * (32 / 4);
319 max_frames -= n_frames;
320 tot_frames += n_frames;
321
Harald Welte51baa362022-01-01 15:22:25 +0100322 /* While DMA is running: Determine if remote end indicates any alarms */
323 for (i = 0; i < n_frames; i++) {
324 unsigned int frame_nr = ofs + i;
325 /* A bit is present in every odd frame TS0 */
326 if (frame_nr & 1) {
327 uint8_t ts0 = *e1_data_ptr(0, ofs + i, 0);
328 rai_possible = true;
329 if (ts0 & 0x20) {
330 rai_received = true;
331 break;
332 }
333 }
334 }
335
Sylvain Munautbc9f5c42020-09-14 10:22:29 +0200336 /* Wait for DMA completion */
337 while (dma_poll());
338 }
339
Harald Welte51baa362022-01-01 15:22:25 +0100340 if (rai_possible) {
341 if (rai_received) {
342 g_e1.errors.flags |= E1_ERR_F_RAI;
343 e1_platform_led_set(0, E1P_LED_YELLOW, E1P_LED_ST_ON);
344 } else {
345 g_e1.errors.flags &= ~E1_ERR_F_RAI;
346 e1_platform_led_set(0, E1P_LED_YELLOW, E1P_LED_ST_OFF);
347 }
348 }
349
Sylvain Munautbc9f5c42020-09-14 10:22:29 +0200350 return tot_frames;
351}
352
353unsigned int
354e1_tx_feed_data(unsigned int usb_addr, unsigned int frames)
355{
356 unsigned int ofs;
357 int n_frames;
358
359 while (frames) {
360 /* Get some space in FIFO */
361 n_frames = e1f_frame_write(&g_e1.tx.fifo, &ofs, frames);
362 if (!n_frames) {
363 printf("[!] TX FIFO Overflow %d %d\n", frames, n_frames);
364 break;
365 }
366
367 /* Copy from USB to FIFO */
368 dma_exec(e1f_ofs_to_dma(ofs), usb_addr, n_frames * (32 / 4), true, NULL, NULL);
369
370 /* Prepare next */
371 usb_addr += n_frames * (32 / 4);
372 frames -= n_frames;
373
374 /* Wait for DMA completion */
375 while (dma_poll());
376 }
377
378 return frames;
379}
380
381unsigned int
382e1_tx_level(void)
383{
384 return e1f_valid_frames(&g_e1.tx.fifo);
385}
386
387unsigned int
388e1_rx_level(void)
389{
390 return e1f_valid_frames(&g_e1.rx.fifo);
391}
392
Harald Welte805f2cf2020-12-14 17:31:03 +0100393const struct e1_error_count *
394e1_get_error_count(void)
395{
396 return &g_e1.errors;
397}
398
Sylvain Munautbc9f5c42020-09-14 10:22:29 +0200399void
400e1_poll(void)
401{
402 uint32_t bd;
403 unsigned int ofs;
404
405 /* Active ? */
406 if ((g_e1.rx.state == IDLE) && (g_e1.tx.state == IDLE))
407 return;
408
409 /* HACK: LED link status */
Harald Welte52765672020-12-15 18:35:42 +0100410 if (e1_regs->rx.csr & E1_RX_SR_ALIGNED) {
411 e1_platform_led_set(0, E1P_LED_GREEN, E1P_LED_ST_ON);
Sylvain Munautbc9f5c42020-09-14 10:22:29 +0200412 led_color(0, 48, 0);
Harald Welte805f2cf2020-12-14 17:31:03 +0100413 g_e1.errors.flags &= ~(E1_ERR_F_LOS|E1_ERR_F_ALIGN_ERR);
Harald Welte52765672020-12-15 18:35:42 +0100414 } else {
415 e1_platform_led_set(0, E1P_LED_GREEN, E1P_LED_ST_BLINK);
Sylvain Munautbc9f5c42020-09-14 10:22:29 +0200416 led_color(48, 0, 0);
Harald Welte805f2cf2020-12-14 17:31:03 +0100417 g_e1.errors.flags |= E1_ERR_F_ALIGN_ERR;
418 /* TODO: completely off if rx tick counter not incrementing */
Harald Welte52765672020-12-15 18:35:42 +0100419 }
Sylvain Munautbc9f5c42020-09-14 10:22:29 +0200420
421 /* Recover any done TX BD */
422 while ( (bd = e1_regs->tx.bd) & E1_BD_VALID ) {
423 e1f_multiframe_read_discard(&g_e1.tx.fifo);
424 g_e1.tx.in_flight--;
425 }
426
427 /* Recover any done RX BD */
428 while ( (bd = e1_regs->rx.bd) & E1_BD_VALID ) {
429 /* FIXME: CRC status ? */
430 e1f_multiframe_write_commit(&g_e1.rx.fifo);
Harald Welte805f2cf2020-12-14 17:31:03 +0100431 if ((bd & (E1_BD_CRC0 | E1_BD_CRC1)) != (E1_BD_CRC0 | E1_BD_CRC1)) {
Sylvain Munautbc9f5c42020-09-14 10:22:29 +0200432 printf("b: %03x\n", bd);
Harald Welte805f2cf2020-12-14 17:31:03 +0100433 g_e1.errors.crc++;
434 }
Sylvain Munautbc9f5c42020-09-14 10:22:29 +0200435 g_e1.rx.in_flight--;
436 }
437
438 /* Boot procedure */
439 if (g_e1.tx.state == BOOT) {
440 if (e1f_unseen_frames(&g_e1.tx.fifo) < (16 * 5))
441 return;
442 /* HACK: LED flow status */
443 led_blink(true, 200, 1000);
444 led_breathe(true, 100, 200);
445 }
446
447 /* Handle RX */
448 /* Misalign ? */
449 if (g_e1.rx.state == RUN) {
450 if (!(e1_regs->rx.csr & E1_RX_SR_ALIGNED)) {
451 printf("[!] E1 rx misalign\n");
452 g_e1.rx.state = RECOVER;
Harald Welte805f2cf2020-12-14 17:31:03 +0100453 g_e1.errors.align++;
Sylvain Munautbc9f5c42020-09-14 10:22:29 +0200454 }
455 }
456
457 /* Overflow ? */
458 if (g_e1.rx.state == RUN) {
459 if (e1_regs->rx.csr & E1_RX_SR_OVFL) {
460 printf("[!] E1 overflow %d\n", g_e1.rx.in_flight);
461 g_e1.rx.state = RECOVER;
Harald Welte805f2cf2020-12-14 17:31:03 +0100462 g_e1.errors.ovfl++;
Sylvain Munautbc9f5c42020-09-14 10:22:29 +0200463 }
464 }
465
466 /* Recover ready ? */
467 if (g_e1.rx.state == RECOVER) {
468 if (g_e1.rx.in_flight != 0)
469 goto done_rx;
470 e1f_multiframe_empty(&g_e1.rx.fifo);
471 }
472
473 /* Fill new RX BD */
474 while (g_e1.rx.in_flight < 4) {
475 if (!e1f_multiframe_write_prepare(&g_e1.rx.fifo, &ofs))
476 break;
477 e1_regs->rx.bd = e1f_ofs_to_mf(ofs);
478 g_e1.rx.in_flight++;
479 }
480
481 /* Clear overflow if needed */
482 if (g_e1.rx.state != RUN) {
483 e1_regs->rx.csr = g_e1.rx.cr | E1_RX_CR_OVFL_CLR;
484 g_e1.rx.state = RUN;
485 }
486done_rx:
487
488 /* Handle TX */
489 /* Underflow ? */
490 if (g_e1.tx.state == RUN) {
491 if (e1_regs->tx.csr & E1_TX_SR_UNFL) {
492 printf("[!] E1 underflow %d\n", g_e1.tx.in_flight);
493 g_e1.tx.state = RECOVER;
Harald Welte805f2cf2020-12-14 17:31:03 +0100494 g_e1.errors.unfl++;
Sylvain Munautbc9f5c42020-09-14 10:22:29 +0200495 }
496 }
497
498 /* Recover ready ? */
499 if (g_e1.tx.state == RECOVER) {
500 if (e1f_unseen_frames(&g_e1.tx.fifo) < (16 * 5))
501 return;
502 }
503
504 /* Fill new TX BD */
505 while (g_e1.tx.in_flight < 4) {
506 if (!e1f_multiframe_read_peek(&g_e1.tx.fifo, &ofs))
507 break;
508 e1_regs->tx.bd = e1f_ofs_to_mf(ofs);
509 g_e1.tx.in_flight++;
510 }
511
512 /* Clear underflow if needed */
513 if (g_e1.tx.state != RUN) {
514 e1_regs->tx.csr = g_e1.tx.cr | E1_TX_CR_UNFL_CLR;
515 g_e1.tx.state = RUN;
516 }
517}
518
519void
520e1_debug_print(bool data)
521{
522 volatile uint8_t *p;
523
524 puts("E1\n");
525 printf("CSR: Rx %04x / Tx %04x\n", e1_regs->rx.csr, e1_regs->tx.csr);
526 printf("InF: Rx %d / Tx %d\n", g_e1.rx.in_flight, g_e1.tx.in_flight);
527 printf("Sta: Rx %d / Tx %d\n", g_e1.rx.state, g_e1.tx.state);
528
529 e1f_debug(&g_e1.rx.fifo, "Rx FIFO");
530 e1f_debug(&g_e1.tx.fifo, "Tx FIFO");
531
532 if (data) {
533 puts("\nE1 Data\n");
534 for (int f=0; f<16; f++) {
535 p = e1_data_ptr(0, f, 0);
536 for (int ts=0; ts<32; ts++)
537 printf(" %02x", p[ts]);
538 printf("\n");
539 }
540 }
541}