/* * Copyright 2017, Data61 * Commonwealth Scientific and Industrial Research Organisation (CSIRO) * ABN 41 687 119 230. * * This software may be distributed and modified according to the terms of * the BSD 2-Clause license. Note that NO WARRANTY is provided. * See "LICENSE_BSD2.txt" for details. * * @TAG(DATA61_BSD) */ #include #include #include #include #include "../../chardev.h" #define UART_REF_CLK 50000000 /* CR */ #define UART_CR_RXRES BIT( 0) #define UART_CR_TXRES BIT( 1) #define UART_CR_RXEN BIT( 2) #define UART_CR_RXDIS BIT( 3) #define UART_CR_TXEN BIT( 4) #define UART_CR_TXDIS BIT( 5) #define UART_CR_RSTTO BIT( 6) #define UART_CR_STTBRK BIT( 7) #define UART_CR_STPBRK BIT( 8) /* MR */ #define UART_MR_CLKS BIT( 0) #define UART_MR_CHRL(x) ((x) * BIT(1)) #define UART_MR_CHRL_MASK UART_MR_CHRL(0x3) #define UART_MR_PAR(x) ((x) * BIT(3)) #define UART_MR_PAR_MASK UART_MR_PAR(0x7) #define UART_MR_NBSTOP(x) ((x) * BIT(6)) #define UART_MR_NBSTOP_MASK UART_MR_NBSTOP(0x3) #define UART_MR_CHMODE(x) ((x) * BIT(8)) #define UART_MR_CHMODE_MASK UART_MR_CHMODE(0x3) /* IER */ #define UART_IER_RTRIG BIT( 0) #define UART_IER_REMPTY BIT( 1) #define UART_IER_RFUL BIT( 2) #define UART_IER_TEMPTY BIT( 3) #define UART_IER_TFUL BIT( 4) #define UART_IER_ROVR BIT( 5) #define UART_IER_FRAME BIT( 6) #define UART_IER_PARE BIT( 7) #define UART_IER_TIMEOUT BIT( 8) #define UART_IER_DMSI BIT( 9) #define UART_IER_TTRIG BIT(10) #define UART_IER_TNFUL BIT(11) #define UART_IER_TOVR BIT(12) /* IDR */ #define UART_IDR_RTRIG BIT( 0) #define UART_IDR_REMPTY BIT( 1) #define UART_IDR_RFUL BIT( 2) #define UART_IDR_TEMPTY BIT( 3) #define UART_IDR_TFUL BIT( 4) #define UART_IDR_ROVR BIT( 5) #define UART_IDR_FRAME BIT( 6) #define UART_IDR_PARE BIT( 7) #define UART_IDR_TIMEOUT BIT( 8) #define UART_IDR_DMSI BIT( 9) #define UART_IDR_TTRIG BIT(10) #define UART_IDR_TNFUL BIT(11) #define UART_IDR_TOVR BIT(12) /* IMR */ #define UART_IMR_RTRIG BIT( 0) #define UART_IMR_REMPTY BIT( 1) #define UART_IMR_RFUL BIT( 2) #define UART_IMR_TEMPTY BIT( 3) #define UART_IMR_TFUL BIT( 4) #define UART_IMR_ROVR BIT( 5) #define UART_IMR_FRAME BIT( 6) #define UART_IMR_PARE BIT( 7) #define UART_IMR_TIMEOUT BIT( 8) #define UART_IMR_DMSI BIT( 9) #define UART_IMR_TTRIG BIT(10) #define UART_IMR_TNFUL BIT(11) #define UART_IMR_TOVR BIT(12) /* ISR */ #define UART_ISR_RTRIG BIT( 0) #define UART_ISR_REMPTY BIT( 1) #define UART_ISR_RFUL BIT( 2) #define UART_ISR_TEMPTY BIT( 3) #define UART_ISR_TFUL BIT( 4) #define UART_ISR_ROVR BIT( 5) #define UART_ISR_FRAME BIT( 6) #define UART_ISR_PARE BIT( 7) #define UART_ISR_TIMEOUT BIT( 8) #define UART_ISR_DMSI BIT( 9) #define UART_ISR_TTRIG BIT(10) #define UART_ISR_TNFUL BIT(11) #define UART_ISR_TOVR BIT(12) /* RXTOUT */ #define UART_RXTOUT_RTO(x) ((x) * BIT(0)) #define UART_RXTOUT_RTO_MASK UART_RXTOUT_RTO(0xFF) /* RXWM */ #define UART_RXWM_RTRIG(x) ((x) * BIT(0)) #define UART_RXWM_RTRIG_MASK UART_RXWM_RTRIG(0x3F) /* MODEMCR */ #define UART_MODEMCR_DTR BIT( 0) #define UART_MODEMCR_RTS BIT( 1) #define UART_MODEMCR_FCM BIT( 5) /* MODEMSR */ #define UART_MODEMSR_DCTS BIT( 0) #define UART_MODEMSR_DDSR BIT( 1) #define UART_MODEMSR_TERI BIT( 2) #define UART_MODEMSR_DDCD BIT( 3) #define UART_MODEMSR_CTS BIT( 4) #define UART_MODEMSR_DSR BIT( 5) #define UART_MODEMSR_RI BIT( 6) #define UART_MODEMSR_DCD BIT( 7) #define UART_MODEMSR_FCMS BIT( 8) /* SR */ #define UART_SR_RTRIG BIT( 0) #define UART_SR_REMPTY BIT( 1) #define UART_SR_RFUL BIT( 2) #define UART_SR_TEMPTY BIT( 3) #define UART_SR_TFUL BIT( 4) #define UART_SR_RACTIVE BIT(10) #define UART_SR_TACTIVE BIT(11) #define UART_SR_FDELT BIT(12) #define UART_SR_TTRIG BIT(13) #define UART_SR_TNFUL BIT(14) /* FLOWDIV */ #define UART_FLOWDIV_FDEL(x) ((x) * BIT(0)) #define UART_FLOWDIV_FDEL_MASK UART_FLOWDIV_FDEL(0x3F) /* TXWM */ #define UART_TXWM_TTRIG(x) ((x) * BIT(0)) #define UART_TXWM_TTRIG_MASK UART_TXWM_TTRIG(0x3F) /* Baud rate dividers */ #define UART_BAUDDIV_BDIV_MIN 4 #define UART_BAUDDIV_BDIV_MAX 255 #define UART_BAUDGEN_CD_MIN 1 #define UART_BAUDGEN_CD_MAX 65535 /* Fifo size */ #define UART_TX_FIFO_SIZE 64 #define UART_RX_FIFO_SIZE 64 struct zynq_uart_regs { uint32_t cr; /* 0x00 Control Register */ uint32_t mr; /* 0x04 Mode Register */ uint32_t ier; /* 0x08 Interrupt Enable Register */ uint32_t idr; /* 0x0C Interrupt Disable Register */ uint32_t imr; /* 0x10 Interrupt Mask Register (read-only) */ uint32_t isr; /* 0x14 Channel Interrupt Status Register (write a 1 to clear) */ uint32_t baudgen; /* 0x18 Baud Rate Generator Register */ uint32_t rxtout; /* 0x1C Receiver Timeout Register */ uint32_t rxwm; /* 0x20 Receiver FIFO Trigger Level Register */ uint32_t modemcr; /* 0x24 Modem Control Register */ uint32_t modemsr; /* 0x28 Modem Status Register */ uint32_t sr; /* 0x2C Channel Status Register (read-only) */ uint32_t fifo; /* 0x30 Transmit and Receive FIFO */ uint32_t bauddiv; /* 0x34 Baud Rate Divider Register */ uint32_t flowdel; /* 0x38 Flow Control Delay Register */ uint32_t pad[2]; uint32_t txwm; /* 0x44 Transmitter FIFO Trigger Level Register */ }; typedef volatile struct zynq_uart_regs zynq_uart_regs_t; static inline zynq_uart_regs_t *zynq_uart_get_priv(ps_chardevice_t *d) { return (zynq_uart_regs_t *)d->vaddr; } static inline void zynq_uart_enable_tx( zynq_uart_regs_t *regs) { regs->cr &= ~UART_CR_TXDIS; regs->cr |= UART_CR_TXEN; } static inline void zynq_uart_enable_rx( zynq_uart_regs_t *regs) { regs->cr &= ~UART_CR_RXDIS; regs->cr |= UART_CR_RXEN; } int uart_getchar( ps_chardevice_t *d) { zynq_uart_regs_t *regs = zynq_uart_get_priv(d); int c = -1; uint32_t imr = regs->imr; regs->idr = imr; if (!(regs->sr & UART_SR_REMPTY)) { c = regs->fifo; /* Clear the Rx timeout interrupt status bit if set. Register * implements the "write a 1 to clear" semantic. */ if (regs->isr & UART_ISR_TIMEOUT) { regs->isr = UART_ISR_TIMEOUT; } } regs->ier = imr; return c; } int uart_putchar( ps_chardevice_t *d, int c) { int ret = -1; zynq_uart_regs_t *regs = zynq_uart_get_priv(d); uint32_t imr = regs->imr; regs->idr = imr; if (c == '\n' && (d->flags & SERIAL_AUTO_CR)) { /* check if 2 bytes are free - tx trigger level is 63 and * this bit is set if the fifo level is >= the trigger level */ if (!(regs->sr & UART_SR_TTRIG)) { regs->fifo = '\r'; regs->fifo = '\n'; ret = '\n'; } } else if (!(regs->sr & UART_SR_TFUL)) { regs->fifo = c; ret = c; } while ((regs->sr & (UART_SR_TEMPTY | UART_SR_TACTIVE)) != UART_SR_TEMPTY); regs->ier = imr; return ret; } static void uart_handle_irq( ps_chardevice_t *d) { zynq_uart_regs_t *regs = zynq_uart_get_priv(d); regs->isr = UART_ISR_RTRIG; } /* * Calculate the baud rate divisors * @param clk: UART module input clock * @param baud: Desired baud rate * @param rdiv8: Calculated MR[CLKS] clock source select value (returned) * @param rcd: Calculated BAUDGEN[CD] baud rate clock divisor value (returned) * @param rbdiv: Calculated BAUDDIV[BDIV] baud rate divider value (returned) * @return : The actual baud rate based on the calculated values */ static long zynq_uart_calc_baud_divs( long clk, long baud, unsigned int *rdiv8, uint32_t *rcd, uint32_t *rbdiv) { /* Safety checks */ assert(rdiv8 != NULL); assert(rcd != NULL); assert(rbdiv != NULL); uint32_t cd, bdiv; long rbaud; unsigned int calc_baud, baud_error, best_baud_error = ~0; /* Calculate the UART clock divisor */ if (baud < clk / ((UART_BAUDDIV_BDIV_MAX + 1) * UART_BAUDGEN_CD_MAX)) { *rdiv8 = 1; clk /= 8; } else { *rdiv8 = 0; } /* Calculate values for CD and BDIV based on the desired baud rate */ for (bdiv = UART_BAUDDIV_BDIV_MIN; bdiv <= UART_BAUDDIV_BDIV_MAX; bdiv++) { cd = clk / (baud * (bdiv + 1)); if (cd < UART_BAUDGEN_CD_MIN || cd > UART_BAUDGEN_CD_MAX) { continue; } calc_baud = clk / (cd * (bdiv + 1)); if (baud > calc_baud) { baud_error = baud - calc_baud; } else { baud_error = calc_baud - baud; } if (baud_error < best_baud_error) { best_baud_error = baud_error; *rcd = cd; *rbdiv = bdiv; rbaud = calc_baud; /* Short-circuit */ if (baud_error == 0) { break; } } } return rbaud; } /* * baud rate = clk / BAUDGEN.CD * (BAUDDIV.BDIV + 1) * BAUDGEN.CD is 16 bit, BAUDDIV.BDIV is 8 bit */ static void zynq_uart_set_baud( ps_chardevice_t *d, long bps) { zynq_uart_regs_t *regs = zynq_uart_get_priv(d); uint32_t cd = 0; uint32_t bdiv = 0; unsigned int div8; zynq_uart_calc_baud_divs(UART_REF_CLK, bps, &div8, &cd, &bdiv); /* Disable the Rx path */ regs->cr &= ~UART_CR_RXEN; /* Disable the Tx path */ regs->cr &= ~UART_CR_TXEN; /* Apply the calculated values */ if (div8) { regs->mr |= UART_MR_CLKS; } else { regs->mr &= ~UART_MR_CLKS; } regs->baudgen = cd; regs->bauddiv = bdiv; /* Reset the Tx and Rx paths */ regs->cr |= UART_CR_TXRES | UART_CR_RXRES; while (regs->cr & (UART_CR_TXRES | UART_CR_RXRES)); /* Enable the Rx path */ zynq_uart_enable_rx(regs); /* Enable the Tx path */ zynq_uart_enable_tx(regs); } int serial_configure( ps_chardevice_t *d, long bps, int char_size, enum serial_parity parity, int stop_bits) { zynq_uart_regs_t *regs = zynq_uart_get_priv(d); uint32_t mr; /* Character size */ mr = regs->mr; if (char_size == 6) { mr &= ~UART_MR_CHRL_MASK; mr |= UART_MR_CHRL(0x3); } else if (char_size == 7) { mr &= ~UART_MR_CHRL_MASK; mr |= UART_MR_CHRL(0x2); } else if (char_size == 8) { mr &= ~UART_MR_CHRL_MASK; } else { return -1; } /* Stop bits */ if (stop_bits == 1) { mr &= ~UART_MR_NBSTOP_MASK; } else if (stop_bits == 2) { mr &= ~UART_MR_NBSTOP_MASK; mr |= UART_MR_NBSTOP(0x2); /* Do not handle 1.5 stop bits for now */ } else { return -1; } /* Parity */ if (parity == PARITY_EVEN) { mr &= ~UART_MR_PAR_MASK; } else if (parity == PARITY_ODD) { mr &= ~UART_MR_PAR_MASK; mr |= UART_MR_PAR(0x1); /* Do not handle forced to 0 parity (space) for now */ /* Do not handle forced to 1 parity (mark) for now */ } else if (parity == PARITY_NONE) { mr &= ~UART_MR_PAR_MASK; mr |= UART_MR_PAR(0x7); } else { return -1; } /* Apply the changes */ regs->mr = mr; #ifndef CONFIG_PLAT_ZYNQMP /* TODO: We don't have a correct reference clock on zynqmp and * therefore rely on the board having been initialised by earlier * loaders. */ /* Now set the board rate */ zynq_uart_set_baud(d, bps); #endif return 0; } static void zynq_uart_dev_init( ps_chardevice_t *dev, const ps_io_ops_t *ops, enum chardev_id id, void *vaddr, const int *irqs) { assert(NULL != dev); memset(dev, 0, sizeof(*dev)); /* Set up all the device properties. */ dev->id = id; dev->vaddr = vaddr; dev->irqs = irqs; dev->read = &uart_read; dev->write = &uart_write; dev->handle_irq = &uart_handle_irq; dev->ioops = *ops; dev->flags = SERIAL_AUTO_CR; } static int zynq_uart_init( ps_chardevice_t *dev) { zynq_uart_regs_t *regs = zynq_uart_get_priv(dev); /* Software reset */ // TODO - UART software reset is done through a different register (UART_RST_CTRL) // TODO - does the I/O signal routing have to be configured here too? /* Configure UART character frame */ serial_configure(dev, 115200, 8, PARITY_NONE, 1); /* Set the level of the RxFIFO trigger level */ regs->rxwm &= ~UART_RXWM_RTRIG_MASK; /* Clear the Rx trigger level */ regs->rxwm |= UART_RXWM_RTRIG(1); /* Set the Rx trigger level to 1 */ /* Enable the RTRIG interrupt */ regs->ier |= UART_IER_RTRIG; /* Set the interrupt enable bit */ regs->idr &= ~UART_IDR_RTRIG; /* Clear the interrupt disable bit */ if (!(regs->imr & UART_IMR_RTRIG)) { /* Verify the interrupt mask value */ return -1; } /* Enable the controller */ regs->cr |= UART_CR_TXRES; /* Reset Tx path */ regs->cr |= UART_CR_RXRES; /* Reset Rx path */ zynq_uart_enable_rx(regs); /* Enable the Rx path */ zynq_uart_enable_tx(regs); /* Enable the Tx path */ regs->cr |= UART_CR_RSTTO; /* Restart the receiver timeout counter */ regs->cr &= ~UART_CR_STTBRK; /* Do not start to transmit a break */ regs->cr |= UART_CR_STPBRK; /* Stop break transmitter */ /* Program the receiver timeout mechanism */ regs->rxtout &= ~UART_RXTOUT_RTO_MASK; /* Disable the timeout mechanism */ /* set the tx trigger to one less than the fifo size so it's possible to check * if there are 2 bytes free */ regs->txwm = UART_TXWM_TTRIG(UART_TX_FIFO_SIZE - 1) & UART_TXWM_TTRIG_MASK; return 0; } int uart_static_init( void *vaddr, const ps_io_ops_t *ops, ps_chardevice_t *dev) { assert(NULL != vaddr); assert(NULL != ops); assert(NULL != dev); /* There is a design quirk here, no context information is passed which * UART this is and what interrupt it uses. So we have set something now * to make this well defined. ZYNQ_UART0 seem a good choice, because this * is what the callers usually want. The contents of the interrupt field * are not used in the driver, so we set this to NULL. */ zynq_uart_dev_init(dev, ops, ZYNQ_UART0, vaddr, NULL); return zynq_uart_init(dev); } int uart_init( const struct dev_defn *defn, const ps_io_ops_t *ops, ps_chardevice_t *dev) { assert(NULL != defn); assert(NULL != ops); assert(NULL != dev); /* Attempt to map the virtual address, assure this works */ void *vaddr = chardev_map(defn, ops); if (vaddr == NULL) { return -1; } zynq_uart_dev_init(dev, ops, defn->id, vaddr, defn->irqs); return zynq_uart_init(dev); }