/* * PL011 Primecell UART driver * * Copyright (C) 2007 Bahadir Balban */ #include #include #include INC_PLAT(platform.h) struct pl011_uart uart; /* UART-specific internal error codes. * TODO: Replace them when generic error codes are in place */ #define PL011_ERROR 1 #define PL011_EAGAIN 2 /* Error status bits in receive status register */ #define PL011_FE (1 << 0) #define PL011_PE (1 << 1) #define PL011_BE (1 << 2) #define PL011_OE (1 << 3) /* Status bits in flag register */ #define PL011_TXFE (1 << 7) #define PL011_RXFF (1 << 6) #define PL011_TXFF (1 << 5) #define PL011_RXFE (1 << 4) #define PL011_BUSY (1 << 3) #define PL011_DCD (1 << 2) #define PL011_DSR (1 << 1) #define PL011_CTS (1 << 0) int pl011_tx_char(unsigned int uart_base, char c) { unsigned int val = 0; read(val, (uart_base + PL011_UARTFR)); if(val & PL011_TXFF) { /* TX FIFO Full */ return -PL011_EAGAIN; } write(c, (uart_base + PL011_UARTDR)); return 0; } int pl011_rx_char(unsigned int uart_base, char * c) { unsigned int data; unsigned int val = 0; read(val, (uart_base + PL011_UARTFR)); if(val & PL011_RXFE) { /* RX FIFO Empty */ return -PL011_EAGAIN; } read(data, (uart_base + PL011_UARTDR)); *c = (char) data; if((data >> 8) & 0xF) { /* There were errors, signal error */ return -1; } return 0; } /* * Sets the baud rate in kbps. It is recommended to use * standard rates such as: 1200, 2400, 3600, 4800, 7200, * 9600, 14400, 19200, 28800, 38400, 57600 76800, 115200. */ void pl011_set_baudrate(unsigned int uart_base, unsigned int baud, \ unsigned int clkrate) { const unsigned int uartclk = 24000000; /* 24Mhz clock fixed on pb926 */ unsigned int val = 0; unsigned int ipart = 0, fpart = 0; /* Use default pb926 rate if no rate is supplied */ if(clkrate == 0) clkrate = uartclk; if(baud > 115200 || baud < 1200) baud = 38400; /* Default rate. */ /* 24000000 / (16 * 38400) */ ipart = 39; write(ipart, (uart_base + PL011_UARTIBRD)); write(fpart, (uart_base + PL011_UARTFBRD)); /* * For the IBAUD and FBAUD to update, we need to * write to UARTLCR_H because the 3 registers are * actually part of a single register in hardware * which only updates by a write to UARTLCR_H */ read(val, (uart_base + PL011_UARTLCR_H)); write(val, (uart_base + PL011_UARTLCR_H)); return; } /* Masks the irqs given in the flags bitvector. */ void pl011_set_irq_mask(unsigned int uart_base, unsigned int flags) { unsigned int val = 0; if(flags > 0x3FF) { /* Invalid irqmask bitvector */ return; } read(val, (uart_base + PL011_UARTIMSC)); val |= flags; write(val, (uart_base + PL011_UARTIMSC)); return; } /* Clears the irqs given in flags from masking */ void pl011_clr_irq_mask(unsigned int uart_base, unsigned int flags) { unsigned int val = 0; if(flags > 0x3FF) { /* Invalid irqmask bitvector */ return; } read(val, (uart_base + PL011_UARTIMSC)); val &= ~flags; write(val, (uart_base + PL011_UARTIMSC)); return; } /* * Produces 1 character from data register and appends it into * rx buffer keeps record of timeout errors if one occurs. */ void pl011_rx_irq_handler(struct pl011_uart * uart, unsigned int flags) { /* * Currently we do nothing for uart irqs, because there's no external * client to send/receive data (e.g. userspace processes kernel threads). */ return; } /* Consumes 1 character from tx buffer and attempts to transmit it */ void pl011_tx_irq_handler(struct pl011_uart * uart, unsigned int flags) { /* * Currently we do nothing for uart irqs, because there's no external * client to send/receive data (e.g. userspace processes kernel threads). */ return; } /* Updates error counts and exits. Does nothing to recover errors */ void pl011_error_irq_handler(struct pl011_uart * uart, unsigned int flags) { if(flags & PL011_FEIRQ) { uart->frame_errors++; } if(flags & PL011_PEIRQ) { uart->parity_errors++; } if(flags & PL011_BEIRQ) { uart->break_errors++; } if(flags & PL011_OEIRQ) { uart->overrun_errors++; } return; } void (* pl011_handlers[]) (struct pl011_uart *, unsigned int) = { 0, /* Modem RI */ 0, /* Modem CTS */ 0, /* Modem DCD */ 0, /* Modem DSR */ &pl011_rx_irq_handler, /* Rx */ &pl011_tx_irq_handler, /* Tx */ &pl011_rx_irq_handler, /* Rx timeout */ &pl011_error_irq_handler, /* Framing error */ &pl011_error_irq_handler, /* Parity error */ &pl011_error_irq_handler, /* Break error */ &pl011_error_irq_handler /* Overrun error */ }; /* UART main entry for irq handling. It redirects actual * handling to handlers relevant to the irq that has occured. */ void pl011_irq_handler(struct pl011_uart * uart) { unsigned int val; int handler_index; void (* handler)(struct pl011_uart *, unsigned int); val = pl011_read_irqstat(uart->base); handler_index = 32 - __clz(val); if(!handler_index) { /* No irq */ return; } /* Jump to right handler */ handler = (void (*) (struct pl011_uart *, unsigned int)) pl011_handlers[handler_index]; /* If a handler is available, call it */ if(handler) (*handler)(uart, val); return; } void pl011_initialise_driver(void) { pl011_initialise_device(&uart); } /* Initialises the uart class data structures, and the device. * Terminal-like operation is assumed for default settings. */ int pl011_initialise_device(struct pl011_uart * uart) { uart->frame_errors = 0; uart->parity_errors = 0; uart->break_errors = 0; uart->overrun_errors = 0; /* Initialise data register for 8 bit data read/writes */ pl011_set_word_width(uart->base, 8); /* * Fifos are disabled because by default it is assumed the port * will be used as a user terminal, and in that case the typed * characters will only show up when fifos are flushed, rather than * when each character is typed. We avoid this by not using fifos. */ pl011_disable_fifos(uart->base); /* Set default baud rate of 38400 */ pl011_set_baudrate(uart->base, 38400, 24000000); /* Set default settings of 1 stop bit, no parity, no hw flow ctrl */ pl011_set_stopbits(uart->base, 1); pl011_parity_disable(uart->base); /* Install the irq handler */ /* TODO: INSTALL IT HERE */ /* Enable all irqs */ pl011_clr_irq_mask(uart->base, 0x3FF); /* Enable rx, tx, and uart chip */ pl011_tx_enable(uart->base); pl011_rx_enable(uart->base); pl011_uart_enable(uart->base); return 0; }