/* * Copyright (c) 2016 Gurjant Kalsi * * Use of this source code is governed by a MIT-style * license that can be found in the LICENSE file or at * https://opensource.org/licenses/MIT */ // TODO(gkalsi): Unify the two UART codepaths and use the port parameter to // select between the real uart and the miniuart. #include #include #include #include #include #include #include #include #include #define RXBUF_SIZE 16 static cbuf_t uart_rx_buf; struct bcm283x_mu_regs { uint32_t io; uint32_t ier; uint32_t iir; uint32_t lcr; uint32_t mcr; uint32_t lsr; uint32_t msr; uint32_t scratch; uint32_t cntl; uint32_t stat; uint32_t baud; }; struct bcm283x_aux_regs { uint32_t auxirq; uint32_t auxenb; }; #define AUX_IRQ_MINIUART (1 << 0) #define AUX_ENB_MINIUART (1 << 0) #define MU_IIR_BYTE_AVAIL (1 << 2) // For reading #define MU_IIR_CLR_XMIT_FIFO (1 << 2) // For writing. #define MU_IIR_CLR_RECV_FIFO (1 << 1) #define MU_IIR_EN_RX_IRQ (1 << 0) // Enable the recv interrupt. #define MU_LSR_TX_EMPTY (1 << 5) static enum handler_return aux_irq(void *arg) { volatile struct bcm283x_mu_regs *mu_regs = (struct bcm283x_mu_regs *)MINIUART_BASE; volatile struct bcm283x_aux_regs *aux_regs = (struct bcm283x_aux_regs *)AUX_BASE; // Make sure this interrupt is intended for the miniuart. uint32_t auxirq = readl(&aux_regs->auxirq); if ((auxirq & AUX_IRQ_MINIUART) == 0) { return INT_NO_RESCHEDULE; } bool resched = false; while (true) { uint32_t iir = readl(&mu_regs->iir); if ((iir & MU_IIR_BYTE_AVAIL) == 0) break; resched = true; char ch = readl(&mu_regs->io); cbuf_write_char(&uart_rx_buf, ch, false); } return resched ? INT_RESCHEDULE : INT_NO_RESCHEDULE; } int uart_putc(int port, char c) { // There's only one UART for now. // TODO(gkalsi): Unify the two UART code paths using the port. struct bcm283x_mu_regs *regs = (struct bcm283x_mu_regs *)MINIUART_BASE; /* Wait until there is space in the FIFO */ while (!(readl(®s->lsr) & MU_LSR_TX_EMPTY)) ; /* Send the character */ writel(c, ®s->io); return 1; } void uart_init(void) { volatile struct bcm283x_mu_regs *mu_regs = (struct bcm283x_mu_regs *)MINIUART_BASE; volatile struct bcm283x_aux_regs *aux_regs = (struct bcm283x_aux_regs *)AUX_BASE; // Create circular buffer to hold received data. cbuf_initialize(&uart_rx_buf, RXBUF_SIZE); // AUX Interrupt handler handles interrupts for SPI1, SPI2, and miniuart // Interrupt handler must decode IRQ. register_int_handler(INTERRUPT_AUX, &aux_irq, NULL); // Enable the Interrupt. unmask_interrupt(INTERRUPT_AUX); writel(MU_IIR_CLR_RECV_FIFO | MU_IIR_CLR_XMIT_FIFO, &mu_regs->iir); // Enable the miniuart peripheral. This also enables Miniuart register // access. It's likely that the VideoCore chip already enables this // peripheral for us, but we hit the enable bit just to be sure. writel(AUX_ENB_MINIUART, &aux_regs->auxenb); // Enable the receive interrupt on the UART peripheral. writel(MU_IIR_EN_RX_IRQ, &mu_regs->ier); } void uart_init_early(void) { } int uart_getc(int port, bool wait) { cbuf_t *rxbuf = &uart_rx_buf; char c; if (cbuf_read_char(rxbuf, &c, wait) == 1) return c; return -1; } void uart_flush_tx(int port) { volatile struct bcm283x_mu_regs *mu_regs = (struct bcm283x_mu_regs *)MINIUART_BASE; writel(MU_IIR_CLR_XMIT_FIFO, &mu_regs->iir); } void uart_flush_rx(int port) { volatile struct bcm283x_mu_regs *mu_regs = (struct bcm283x_mu_regs *)MINIUART_BASE; writel(MU_IIR_CLR_RECV_FIFO, &mu_regs->iir); } void uart_init_port(int port, uint baud) { }