|
@@ -11,88 +11,41 @@
|
|
|
|
|
|
#define BAUD 3000000 /* 3Mbaud */
|
|
|
|
|
|
-#define DMA1_CH4_IRQ 14
|
|
|
-void IRQ_14(void) __attribute__((alias("IRQ_dma1_ch4_tc")));
|
|
|
-
|
|
|
#define USART1_IRQ 37
|
|
|
|
|
|
-/* We stage serial output in a ring buffer. DMA occurs from the ring buffer;
|
|
|
- * the consumer index being updated each time a DMA sequence completes. */
|
|
|
-static char ring[2048];
|
|
|
-#define MASK(x) ((x)&(sizeof(ring)-1))
|
|
|
-static unsigned int cons, prod, dma_sz;
|
|
|
-
|
|
|
-/* The console can be set into synchronous mode in which case DMA is disabled
|
|
|
- * and the transmit-empty flag is polled manually for each byte. */
|
|
|
-static bool_t sync_console;
|
|
|
-
|
|
|
-static void kick_tx(void)
|
|
|
+static void ser_putc(uint8_t c)
|
|
|
{
|
|
|
- if (sync_console) {
|
|
|
-
|
|
|
- while (cons != prod) {
|
|
|
- while (!(usart1->sr & USART_SR_TXE))
|
|
|
- cpu_relax();
|
|
|
- usart1->dr = ring[MASK(cons++)];
|
|
|
- }
|
|
|
-
|
|
|
- } else if (!dma_sz && (cons != prod)) {
|
|
|
-
|
|
|
- dma_sz = min(MASK(prod-cons), sizeof(ring)-MASK(cons));
|
|
|
- dma1->ch4.cmar = (uint32_t)(unsigned long)&ring[MASK(cons)];
|
|
|
- dma1->ch4.cndtr = dma_sz;
|
|
|
- dma1->ch4.ccr = (DMA_CCR_MSIZE_8BIT |
|
|
|
- /* The manual doesn't allow byte accesses to usart. */
|
|
|
- DMA_CCR_PSIZE_16BIT |
|
|
|
- DMA_CCR_MINC |
|
|
|
- DMA_CCR_DIR_M2P |
|
|
|
- DMA_CCR_TCIE |
|
|
|
- DMA_CCR_EN);
|
|
|
-
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-static void IRQ_dma1_ch4_tc(void)
|
|
|
-{
|
|
|
- /* Clear the DMA controller. */
|
|
|
- dma1->ch4.ccr = 0;
|
|
|
- dma1->ifcr = DMA_IFCR_CGIF(4);
|
|
|
-
|
|
|
- /* Update ring state. */
|
|
|
- cons += dma_sz;
|
|
|
- dma_sz = 0;
|
|
|
-
|
|
|
- /* Kick off more transmit activity. */
|
|
|
- kick_tx();
|
|
|
+ while (!(usart1->sr & USART_SR_TXE))
|
|
|
+ cpu_relax();
|
|
|
+ usart1->dr = c;
|
|
|
}
|
|
|
|
|
|
int vprintk(const char *format, va_list ap)
|
|
|
{
|
|
|
static char str[128];
|
|
|
+ unsigned int flags;
|
|
|
char *p, c;
|
|
|
int n;
|
|
|
|
|
|
- IRQ_global_disable();
|
|
|
+ IRQ_global_save(flags);
|
|
|
|
|
|
n = vsnprintf(str, sizeof(str), format, ap);
|
|
|
|
|
|
p = str;
|
|
|
- while (((c = *p++) != '\0') && ((prod-cons) != (sizeof(ring) - 1))) {
|
|
|
+ while ((c = *p++) != '\0') {
|
|
|
switch (c) {
|
|
|
case '\r': /* CR: ignore as we generate our own CR/LF */
|
|
|
break;
|
|
|
case '\n': /* LF: convert to CR/LF (usual terminal behaviour) */
|
|
|
- ring[MASK(prod++)] = '\r';
|
|
|
+ ser_putc('\r');
|
|
|
/* fall through */
|
|
|
default:
|
|
|
- ring[MASK(prod++)] = c;
|
|
|
+ ser_putc(c);
|
|
|
break;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- kick_tx();
|
|
|
-
|
|
|
- IRQ_global_enable();
|
|
|
+ IRQ_global_restore(flags);
|
|
|
|
|
|
return n;
|
|
|
}
|
|
@@ -109,23 +62,6 @@ int printk(const char *format, ...)
|
|
|
return n;
|
|
|
}
|
|
|
|
|
|
-void console_sync(void)
|
|
|
-{
|
|
|
- if (sync_console)
|
|
|
- return;
|
|
|
-
|
|
|
- IRQ_global_disable();
|
|
|
-
|
|
|
- sync_console = TRUE;
|
|
|
-
|
|
|
- /* Wait for DMA completion and then kick off synchronous mode. */
|
|
|
- while (dma1->ch4.cndtr)
|
|
|
- cpu_relax();
|
|
|
- IRQ_dma1_ch4_tc();
|
|
|
-
|
|
|
- /* Leave IRQs globally disabled. */
|
|
|
-}
|
|
|
-
|
|
|
void console_init(void)
|
|
|
{
|
|
|
/* Turn on the clocks. */
|
|
@@ -139,12 +75,6 @@ void console_init(void)
|
|
|
usart1->brr = SYSCLK / BAUD;
|
|
|
usart1->cr1 = (USART_CR1_UE | USART_CR1_TE | USART_CR1_RE);
|
|
|
usart1->cr3 = USART_CR3_DMAT;
|
|
|
-
|
|
|
- /* Initialise DMA1 channel 4 and its completion interrupt. */
|
|
|
- dma1->ch4.cpar = (uint32_t)(unsigned long)&usart1->dr;
|
|
|
- dma1->ifcr = DMA_IFCR_CGIF(4);
|
|
|
- IRQx_set_prio(DMA1_CH4_IRQ, CONSOLE_IRQ_PRI);
|
|
|
- IRQx_enable(DMA1_CH4_IRQ);
|
|
|
}
|
|
|
|
|
|
/* Debug helper: if we get stuck somewhere, calling this beforehand will cause
|