1/** 2 * \file 3 * \brief Kernel serial driver for the OMAP44xx UARTs. 4 */ 5 6/* 7 * Copyright (c) 2012-2015, ETH Zurich. 8 * All rights reserved. 9 * 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, Haldeneggsteig 4, CH-8092 Zurich. Attn: Systems Group. 13 */ 14 15#include <omap_uart.h> 16#include <dev/omap/omap44xx_uart3_dev.h> 17#include <kernel.h> 18#include <arm.h> 19#include <paging_kernel_arch.h> 20#include <platform.h> 21#include <serial.h> 22 23// 24// Serial console and debugger interfaces 25// 26#define NUM_PORTS 4 27static omap44xx_uart3_t ports[NUM_PORTS]; 28 29static void omap_uart_hw_init(omap44xx_uart3_t *uart); 30 31#define MSG(port, format, ...) \ 32 printk( LOG_NOTE, "OMAP serial[%d]: "format, port, ## __VA_ARGS__ ) 33 34/* 35 * Initialize UARTs before the MMU is on. 36 */ 37errval_t serial_early_init(unsigned port) 38{ 39 assert(!paging_mmu_enabled()); 40 assert(port < serial_num_physical_ports); 41 omap44xx_uart3_initialize(&ports[port], (mackerel_addr_t)uart_base[port]); 42 omap_uart_hw_init(&ports[port]); 43 return SYS_ERR_OK; 44} 45 46/* 47 * Re-initialize UARTs after the MMU is on. 48 */ 49void omap_uart_init(unsigned port, lvaddr_t base, bool initialize_hw) 50{ 51 assert(paging_mmu_enabled()); 52 assert(port < serial_num_physical_ports); 53 omap44xx_uart3_initialize(&ports[port], (mackerel_addr_t)base); 54 if (initialize_hw) omap_uart_hw_init(&ports[port]); 55} 56 57static void 58uart_reset(omap44xx_uart3_t *uart) { 59 /* Do soft reset */ 60 omap44xx_uart3_sysc_softreset_wrf(uart, 1); 61 while(!omap44xx_uart3_syss_resetdone_rdf(uart)); // Poll for completion 62} 63 64static void 65init_fifos(omap44xx_uart3_t *uart) { 66 /* Configure FIFOs and DMA. TRM S23.3.5.1.1.2. */ 67 omap44xx_uart3_lcr_t lcr_reset= omap44xx_uart3_lcr_rd(uart); 68 69 /* Set configuration mode B. */ 70 omap44xx_uart3_lcr_wr(uart, (omap44xx_uart3_lcr_t)0x00BF); // Step 1(b) 71 72 /* Enable register submode TCR_TLR (part 1). */ 73 int enhanced_en_reset= omap44xx_uart3_efr_enhanced_en_rdf(uart); 74 omap44xx_uart3_efr_enhanced_en_wrf(uart, 1); 75 76 /* Set configuration mode A. */ 77 omap44xx_uart3_lcr_wr(uart, (omap44xx_uart3_lcr_t)0x0080); // Step 3 78 79 /* Enable register submode TCR_TLR (part 2). */ 80 int tcr_tlr_reset= omap44xx_uart3_mcr_tcr_tlr_rdf(uart); 81 omap44xx_uart3_mcr_tcr_tlr_wrf(uart, 1); 82 83 /* Disable FIFOs, and set send and receive triggers to one byte. */ 84 omap44xx_uart3_fcr_rx_fifo_trig_wrf(uart, 0x1); // Low 2 bits 85 omap44xx_uart3_fcr_tx_fifo_trig_wrf(uart, 0x1); 86 omap44xx_uart3_fcr_dma_mode_wrf(uart, 0); // Ignored 87 omap44xx_uart3_fcr_fifo_en_wrf(uart, 0); 88 89 /* Reset Tx and Rx FIFOs. */ 90 omap44xx_uart3_fcr_tx_fifo_clear_wrf(uart, 1); 91 omap44xx_uart3_fcr_rx_fifo_clear_wrf(uart, 1); 92 93 /* Set configuration mode B. */ 94 omap44xx_uart3_lcr_wr(uart, (omap44xx_uart3_lcr_t)0x00BF); // Step 6 95 96 /* Set the upper 4 bits of the trigger levels to zero. */ 97 omap44xx_uart3_tlr_rx_fifo_trig_dma_wrf(uart, 0x0); 98 omap44xx_uart3_tlr_tx_fifo_trig_dma_wrf(uart, 0x0); 99 100 /* Disable DMA, and set trigger levels using both tlr_rx_fifo_trig_dma 101 * (high 4 bits), and fcr_rx_fifo_trig (low 2 bits). */ 102 omap44xx_uart3_scr_rx_trig_granu1_wrf(uart, 1); 103 omap44xx_uart3_scr_tx_trig_granu1_wrf(uart, 1); 104 omap44xx_uart3_scr_dma_mode_2_wrf(uart, 0); 105 omap44xx_uart3_scr_dma_mode_ctl_wrf(uart, 1); 106 107 /* Restore enhanced_en. */ 108 omap44xx_uart3_efr_enhanced_en_wrf(uart, enhanced_en_reset); 109 110 /* Set configuration mode A. */ 111 omap44xx_uart3_lcr_wr(uart, (omap44xx_uart3_lcr_t)0x0080); // Step 10 112 113 /* Restore tcr_tlr. */ 114 omap44xx_uart3_mcr_tcr_tlr_wrf(uart, tcr_tlr_reset); 115 116 /* Restore LCR. */ 117 omap44xx_uart3_lcr_wr(uart, lcr_reset); 118} 119 120static void 121init_protocol(omap44xx_uart3_t *uart) { 122 /* Configure protocol, baud rate and interrupts. TRM S13.3.5.1.1.4. */ 123 124 /* Disable UART, to access DLL and DLH. */ 125 omap44xx_uart3_mdr1_mode_select_wrf(uart, omap44xx_uart3_MODE_SELECT_7); 126 127 /* Set configuration mode B. */ 128 omap44xx_uart3_lcr_wr(uart, (omap44xx_uart3_lcr_t)0x00BF); 129 130 /* Enable access to IER[7:4] bit field. */ 131 int enhanced_en_reset= omap44xx_uart3_efr_enhanced_en_rdf(uart); 132 omap44xx_uart3_efr_enhanced_en_wrf(uart, 1); 133 134 /* Switch to register operational mode. */ 135 omap44xx_uart3_lcr_wr(uart, (omap44xx_uart3_lcr_t)0x0000); // Step 4 136 137 /* Clear the interrupt enable register. */ 138 omap44xx_uart3_ier_wr(uart, (omap44xx_uart3_ier_t)0x0000); // Step 5 139 140 /* Set configuration mode B. */ 141 omap44xx_uart3_lcr_wr(uart, (omap44xx_uart3_lcr_t)0x00BF); 142 143 /* Set the Baud rate divisor for ~115200bps, from a 48MHz clock. 144 * We'll set 16x mode, so 115385 ~ 48MHz / (16 * 26). */ 145 omap44xx_uart3_dlh_clock_msb_wrf(uart, 0); 146 omap44xx_uart3_dll_clock_lsb_wrf(uart, 26); 147 148 /* Switch to register operational mode. */ 149 omap44xx_uart3_lcr_wr(uart, (omap44xx_uart3_lcr_t)0x0000); 150 151 /* Enable the receive interrupt. */ 152 omap44xx_uart3_ier_rhr_it_wrf(uart, 1); 153 154 /* Set configuration mode B. */ 155 omap44xx_uart3_lcr_wr(uart, (omap44xx_uart3_lcr_t)0x00BF); 156 157 /* Restore enhanced_en. */ 158 omap44xx_uart3_efr_enhanced_en_wrf(uart, enhanced_en_reset); 159 160 /* Set protocol formatting (8n1). */ 161 omap44xx_uart3_lcr_div_en_wrf(uart, 0); 162 omap44xx_uart3_lcr_break_en_wrf(uart, 0); 163 omap44xx_uart3_lcr_parity_en_wrf(uart, 0); 164 omap44xx_uart3_lcr_nb_stop_wrf(uart, omap44xx_uart3_NB_STOP_0); 165 omap44xx_uart3_lcr_char_length_wrf(uart, omap44xx_uart3_cl8); 166 167 /* Set UART to 16x mode. */ 168 omap44xx_uart3_mdr1_mode_select_wrf(uart, 0); 169} 170 171/* 172 * Initialise OMAP UART hardware 173 * UART TRM 23.3 174 */ 175static void omap_uart_hw_init(omap44xx_uart3_t *uart) 176{ 177 uart_reset(uart); 178 init_fifos(uart); 179 init_protocol(uart); 180} 181 182/** 183 * \brief Prints a single character to a serial port. 184 */ 185void serial_putchar(unsigned port, char c) 186{ 187 assert(port <= NUM_PORTS); 188 omap44xx_uart3_t *uart = &ports[port]; 189 190 // Wait until FIFO can hold more characters 191 while(!omap44xx_uart3_lsr_tx_fifo_e_rdf(uart)); 192 193 // Write character 194 omap44xx_uart3_thr_thr_wrf(uart, c); 195} 196 197/** 198 * \brief Reads a single character from the default serial port. 199 */ 200char serial_getchar(unsigned port) 201{ 202 assert(port <= NUM_PORTS); 203 omap44xx_uart3_t *uart = &ports[port]; 204 205 /* Read until the interrupt is deasserted. */ 206 char c= '\0'; 207 while(omap44xx_uart3_iir_it_pending_rdf(uart) == 0) { 208 c= omap44xx_uart3_rhr_rhr_rdf(uart); 209 } 210 211 return c; 212} 213