/** * \file * \brief Kernel serial driver for the OMAP44xx UARTs. */ /* * Copyright (c) 2012-2015, ETH Zurich. * All rights reserved. * * This file is distributed under the terms in the attached LICENSE file. * If you do not find this file, copies can be found by writing to: * ETH Zurich D-INFK, Universitaetstrasse 6, CH-8092 Zurich. Attn: Systems Group. */ #include #include #include #include #include #include #include // // Serial console and debugger interfaces // #define NUM_PORTS 4 static omap44xx_uart3_t ports[NUM_PORTS]; static void omap_uart_hw_init(omap44xx_uart3_t *uart); #define MSG(port, format, ...) \ printk( LOG_NOTE, "OMAP serial[%d]: "format, port, ## __VA_ARGS__ ) /* * Initialize UARTs before the MMU is on. */ errval_t serial_early_init(unsigned port) { assert(!paging_mmu_enabled()); assert(port < serial_num_physical_ports); omap44xx_uart3_initialize(&ports[port], (mackerel_addr_t)platform_uart_base[port]); omap_uart_hw_init(&ports[port]); return SYS_ERR_OK; } /* * Re-initialize UARTs after the MMU is on. */ void omap_uart_init(unsigned port, lvaddr_t base, bool initialize_hw) { assert(paging_mmu_enabled()); assert(port < serial_num_physical_ports); omap44xx_uart3_initialize(&ports[port], (mackerel_addr_t)base); if (initialize_hw) omap_uart_hw_init(&ports[port]); } static void uart_reset(omap44xx_uart3_t *uart) { /* Do soft reset */ omap44xx_uart3_sysc_softreset_wrf(uart, 1); while(!omap44xx_uart3_syss_resetdone_rdf(uart)); // Poll for completion } static void init_fifos(omap44xx_uart3_t *uart) { /* Configure FIFOs and DMA. TRM S23.3.5.1.1.2. */ omap44xx_uart3_lcr_t lcr_reset= omap44xx_uart3_lcr_rd(uart); /* Set configuration mode B. */ omap44xx_uart3_lcr_wr(uart, (omap44xx_uart3_lcr_t)0x00BF); // Step 1(b) /* Enable register submode TCR_TLR (part 1). */ int enhanced_en_reset= omap44xx_uart3_efr_enhanced_en_rdf(uart); omap44xx_uart3_efr_enhanced_en_wrf(uart, 1); /* Set configuration mode A. */ omap44xx_uart3_lcr_wr(uart, (omap44xx_uart3_lcr_t)0x0080); // Step 3 /* Enable register submode TCR_TLR (part 2). */ int tcr_tlr_reset= omap44xx_uart3_mcr_tcr_tlr_rdf(uart); omap44xx_uart3_mcr_tcr_tlr_wrf(uart, 1); /* Disable FIFOs, and set send and receive triggers to one byte. */ omap44xx_uart3_fcr_rx_fifo_trig_wrf(uart, 0x1); // Low 2 bits omap44xx_uart3_fcr_tx_fifo_trig_wrf(uart, 0x1); omap44xx_uart3_fcr_dma_mode_wrf(uart, 0); // Ignored omap44xx_uart3_fcr_fifo_en_wrf(uart, 0); /* Reset Tx and Rx FIFOs. */ omap44xx_uart3_fcr_tx_fifo_clear_wrf(uart, 1); omap44xx_uart3_fcr_rx_fifo_clear_wrf(uart, 1); /* Set configuration mode B. */ omap44xx_uart3_lcr_wr(uart, (omap44xx_uart3_lcr_t)0x00BF); // Step 6 /* Set the upper 4 bits of the trigger levels to zero. */ omap44xx_uart3_tlr_rx_fifo_trig_dma_wrf(uart, 0x0); omap44xx_uart3_tlr_tx_fifo_trig_dma_wrf(uart, 0x0); /* Disable DMA, and set trigger levels using both tlr_rx_fifo_trig_dma * (high 4 bits), and fcr_rx_fifo_trig (low 2 bits). */ omap44xx_uart3_scr_rx_trig_granu1_wrf(uart, 1); omap44xx_uart3_scr_tx_trig_granu1_wrf(uart, 1); omap44xx_uart3_scr_dma_mode_2_wrf(uart, 0); omap44xx_uart3_scr_dma_mode_ctl_wrf(uart, 1); /* Restore enhanced_en. */ omap44xx_uart3_efr_enhanced_en_wrf(uart, enhanced_en_reset); /* Set configuration mode A. */ omap44xx_uart3_lcr_wr(uart, (omap44xx_uart3_lcr_t)0x0080); // Step 10 /* Restore tcr_tlr. */ omap44xx_uart3_mcr_tcr_tlr_wrf(uart, tcr_tlr_reset); /* Restore LCR. */ omap44xx_uart3_lcr_wr(uart, lcr_reset); } static void init_protocol(omap44xx_uart3_t *uart) { /* Configure protocol, baud rate and interrupts. TRM S13.3.5.1.1.4. */ /* Disable UART, to access DLL and DLH. */ omap44xx_uart3_mdr1_mode_select_wrf(uart, omap44xx_uart3_MODE_SELECT_7); /* Set configuration mode B. */ omap44xx_uart3_lcr_wr(uart, (omap44xx_uart3_lcr_t)0x00BF); /* Enable access to IER[7:4] bit field. */ int enhanced_en_reset= omap44xx_uart3_efr_enhanced_en_rdf(uart); omap44xx_uart3_efr_enhanced_en_wrf(uart, 1); /* Switch to register operational mode. */ omap44xx_uart3_lcr_wr(uart, (omap44xx_uart3_lcr_t)0x0000); // Step 4 /* Clear the interrupt enable register. */ omap44xx_uart3_ier_wr(uart, (omap44xx_uart3_ier_t)0x0000); // Step 5 /* Set configuration mode B. */ omap44xx_uart3_lcr_wr(uart, (omap44xx_uart3_lcr_t)0x00BF); /* Set the Baud rate divisor for ~115200bps, from a 48MHz clock. * We'll set 16x mode, so 115385 ~ 48MHz / (16 * 26). */ omap44xx_uart3_dlh_clock_msb_wrf(uart, 0); omap44xx_uart3_dll_clock_lsb_wrf(uart, 26); /* Switch to register operational mode. */ omap44xx_uart3_lcr_wr(uart, (omap44xx_uart3_lcr_t)0x0000); /* Enable the receive interrupt. */ omap44xx_uart3_ier_rhr_it_wrf(uart, 1); /* Set configuration mode B. */ omap44xx_uart3_lcr_wr(uart, (omap44xx_uart3_lcr_t)0x00BF); /* Restore enhanced_en. */ omap44xx_uart3_efr_enhanced_en_wrf(uart, enhanced_en_reset); /* Set protocol formatting (8n1). */ omap44xx_uart3_lcr_div_en_wrf(uart, 0); omap44xx_uart3_lcr_break_en_wrf(uart, 0); omap44xx_uart3_lcr_parity_en_wrf(uart, 0); omap44xx_uart3_lcr_nb_stop_wrf(uart, omap44xx_uart3_NB_STOP_0); omap44xx_uart3_lcr_char_length_wrf(uart, omap44xx_uart3_cl8); /* Set UART to 16x mode. */ omap44xx_uart3_mdr1_mode_select_wrf(uart, 0); } /* * Initialise OMAP UART hardware * UART TRM 23.3 */ static void omap_uart_hw_init(omap44xx_uart3_t *uart) { uart_reset(uart); init_fifos(uart); init_protocol(uart); } /** * \brief Prints a single character to a serial port. */ void serial_putchar(unsigned port, char c) { assert(port <= NUM_PORTS); omap44xx_uart3_t *uart = &ports[port]; // Wait until FIFO can hold more characters while(!omap44xx_uart3_lsr_tx_fifo_e_rdf(uart)); // Write character omap44xx_uart3_thr_thr_wrf(uart, c); } /** * \brief Reads a single character from the default serial port. */ char serial_getchar(unsigned port) { assert(port <= NUM_PORTS); omap44xx_uart3_t *uart = &ports[port]; /* Read until the interrupt is deasserted. */ char c= '\0'; while(omap44xx_uart3_iir_it_pending_rdf(uart) == 0) { c= omap44xx_uart3_rhr_rhr_rdf(uart); } return c; }