- Main Page
- Related Pages
- Data Structures
- Files

- File List
- Globals

# drivers/console/serial.c

Go to the documentation of this file.

    00001
    00045 #include <assert.h>
    00046 #include <interrupt.h>
    00047 #include <status-codes.h>
    00048 #include <util.h>
    00049
    00050 #include <chip/clk.h>
    00051 #include <console/core.h>
    00052 #include <console/driver.h>
    00053 #include <console/serial.h>
    00054 #include <hardware/usart.h>
    00055
    00056 struct usart_port {
    00057         void                    *regs;
    00058         unsigned long           pclk_hz;
    00059         struct console_driver   drv;
    00060 };
    00061
    00062 static inline struct usart_port *usart_port_of(struct console_driver *drv)
    00063 {
    00064         return container_of(drv, struct usart_port, drv);
    00065 }
    00066
    00067 static void usart_tx_commit(struct console_driver *drv)
    00068 {
    00069         struct usart_port       *usart = usart_port_of(drv);
    00070         void                    *regs = usart->regs;
    00071         unsigned long           nchars;
    00072         unsigned long           iflags;
    00073         char                    c;
    00074
    00075         iflags = cpu_irq_save();
    00076         while (true) {
    00077                 nchars = console_buf_used(&drv->tx_buf);
    00078                 assert(nchars <= CONSOLE_BUF_SIZE);
    00079                 if (nchars == 0)
    00080                         break;
    00081
    00082                 c = console_buf_extract_char(&drv->tx_buf);
    00083                 cpu_irq_restore(iflags);
    00084
    00085                 while (!(usart_read(regs, CSR) & USART_BIT(TXRDY)))
    00086                         barrier();
    00087
    00088                 usart_write(regs, THR, c);
    00089                 iflags = cpu_irq_save();
    00090         }
    00091         cpu_irq_restore(iflags);
    00092 }
    00093
    00094 static void usart_tx_make_room(struct console_driver *drv, size_t goal)
    00095 {
    00096         /* Keep it simple for now */
    00097         usart_tx_commit(drv);
    00098 }
    00099
    00100 /* FIXME: Support multiple ports */
    00101 static struct usart_port the_usart_port = {
    00102         .drv.tx_commit = usart_tx_commit,
    00103         .drv.tx_make_room = usart_tx_make_room,
    00104 };
    00105
    00117 static uint32_t usart_calc_brgr(unsigned long base_hz, unsigned long baud)
    00118 {
    00119         unsigned long div;
    00120         unsigned long cd;
    00121         unsigned long fp;
    00122
    00123         div = (base_hz + baud / 2) / baud;
    00124         cd = div / 8;
    00125         fp = div % 8;
    00126
    00127         if (cd < 2 || (cd & ((1 << USART_CD_SIZE) - 1)) != cd)
    00128                 return 0;
    00129
    00130         return USART_BF(CD, cd) | USART_BF(FP, fp);
    00131 }
    00132
    00133 int __serial_console_init(struct console *con, unsigned int port, void *regs,
    00134                 unsigned long baud_rate, unsigned long flags)
    00135 {
    00136         struct usart_port       *usart = &the_usart_port;
    00137         unsigned long           pclk_hz;
    00138         uint32_t                cr_flags = 0;
    00139
    00140         if (flags & SERIAL_ENABLE_TX)
    00141                 cr_flags |= USART_BIT(TXEN);
    00142
    00143         /* We don't actually support RX yet... */
    00144         if (flags & SERIAL_ENABLE_RX)
    00145                 cr_flags |= USART_BIT(RXEN);
    00146
    00147         pclk_hz = get_usart_pclk_rate(port);
    00148         usart->pclk_hz = pclk_hz;
    00149         usart->regs = regs;
    00150
    00151         /* If the USART has already been initialized, don't touch anything */
    00152         if (!usart_read(regs, BRGR)) {
    00153                 uint32_t        brgr;
    00154                 uint32_t        mr;
    00155
    00156                 mr = USART_BF(MODE, USART_MODE_NORMAL)
    00157                         | USART_BF(USCLKS, USART_USCLKS_MCK)
    00158                         | USART_BF(CHRL, USART_CHRL_8)
    00159                         | USART_BF(PAR, USART_PAR_NONE)
    00160                         | USART_BF(NBSTOP, USART_NBSTOP_1);
    00161
    00162                 brgr = usart_calc_brgr((pclk_hz + 1) / 2, baud_rate);
    00163                 if (!brgr) {
    00164                         brgr = usart_calc_brgr(pclk_hz, baud_rate);
    00165                         if (!brgr)
    00166                                 return -STATUS_INVALID_PARAM;
    00167                         mr |= USART_BIT(OVER);
    00168                 }
    00169
    00170                 usart_write(regs, CR, USART_BIT(RSTRX) | USART_BIT(RSTTX));
    00171                 usart_write(regs, BRGR, brgr);
    00172                 usart_write(regs, MR, mr);
    00173         }
    00174
    00175         usart_write(regs, CR, cr_flags);
    00176
    00177         con->drv = &usart->drv;
    00178
    00179         return 0;
    00180 }