3 * \brief ARM pl011 UART kernel-level driver.
7 * Copyright (c) 2007, 2008, ETH Zurich.
10 * This file is distributed under the terms in the attached LICENSE file.
11 * If you do not find this file, copies can be found by writing to:
12 * ETH Zurich D-INFK, Universitaetstrasse 6, CH-8092 Zurich. Attn: Systems Group.
15 #include <arch/arm/lpuart.h>
17 #include <paging_kernel_arch.h>
18 #include <arch/arm/arm.h>
19 #include <arch/arm/platform.h>
21 #include <dev/lpuart_dev.h>
23 static lpuart_t uarts[LPUART_MAX_PORTS];
25 // Mask all interrupts in the IMSC register
26 #define INTERRUPTS_MASK 0
28 #define MSG(format, ...) printk( LOG_NOTE, "lpuart: "format, ## __VA_ARGS__ )
30 static void lpuart_hw_init(lpuart_t *uart);
33 * \brief Configure the serial interface, from a caller that knows
34 * that this is a bunch of PL011s, and furthermore where they are in
35 * the physical address space.
37 errval_t serial_early_init(unsigned n)
39 assert(!paging_mmu_enabled());
40 assert(n < serial_num_physical_ports);
42 lpuart_initialize(&uarts[n],
43 (mackerel_addr_t)local_phys_to_mem(platform_uart_base[n]));
45 // Make sure that the UART is enabled and transmitting - not all platforms
47 lpuart_hw_init(&uarts[n]);
53 * \brief Configure the serial interface, from a caller that knows
54 * that this is a bunch of PL011s, and furthermore where they are in
55 * the physical address space.
57 errval_t serial_early_init_mmu_enabled(unsigned n)
59 assert(paging_mmu_enabled());
60 assert(n < serial_num_physical_ports);
62 lpuart_initialize(&uarts[n],
63 (mackerel_addr_t)local_phys_to_mem(platform_uart_base[n]));
65 // Make sure that the UART is enabled and transmitting - not all platforms
67 lpuart_hw_init(&uarts[n]);
72 * \brief Initialize a serial port. The MMU is turned on.
74 void lpuart_init(unsigned port, lvaddr_t base, bool hwinit)
76 assert(paging_mmu_enabled());
77 assert(port < serial_num_physical_ports);
79 lpuart_t *u = &uarts[port];
81 // [Re]initialize the Mackerel state for the UART
82 lpuart_initialize(u, (mackerel_addr_t) base);
89 static void lpuart_hw_init(lpuart_t *uart)
91 // Disable transceiver
92 lpuart_ctrl_t ctrl = lpuart_ctrl_rawrd(uart);
93 ctrl = lpuart_ctrl_te_insert(ctrl, 0);
94 ctrl = lpuart_ctrl_re_insert(ctrl, 0);
95 lpuart_ctrl_rawwr(uart, ctrl);
97 //TODO: Figure out more advanced configuration (FIFO etc.)
100 // baudrate = clock rate / (over sampling rate * SBR)
101 // TODO: Currently we assume UART clock is set to 8MHz
102 lpuart_baud_t baud = lpuart_baud_default;
103 baud = lpuart_baud_osr_insert(baud, lpuart_ratio5);
104 // OSR of 5 needs bothedge set
105 baud = lpuart_baud_bothedge_insert(baud, 1);
106 baud = lpuart_baud_sbr_insert(baud, 139);
107 lpuart_baud_rawwr(uart, baud);
109 // Enable transceiver
110 ctrl = lpuart_ctrl_default;
111 ctrl = lpuart_ctrl_te_insert(ctrl, 1);
112 ctrl = lpuart_ctrl_re_insert(ctrl, 1);
113 lpuart_ctrl_rawwr(uart, ctrl);
117 * \brief Put a character to the port
119 void serial_putchar(unsigned port, char c)
121 assert(port < LPUART_MAX_PORTS);
122 lpuart_t *u = &uarts[port];
123 assert(u->base != 0);
125 while(lpuart_stat_tdre_rdf(u) == 0);
127 lpuart_txdata_t txdata = lpuart_txdata_default;
128 // We don't handle break/idle char currently
129 txdata = lpuart_txdata_tsc_insert(txdata, 0);
130 txdata = lpuart_txdata_buf_insert(txdata, c);
131 lpuart_txdata_wr(u, txdata);
135 * \brief Read a character from a port
137 char serial_getchar(unsigned port)
139 assert(port < LPUART_MAX_PORTS);
140 lpuart_t *u = &uarts[port];
141 assert(u->base != 0);
144 while(lpuart_stat_rdrf_rdf(u) == 0);
146 return (char)lpuart_rxdata_buf_rdf(u);