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