213 lines
6.5 KiB
C
213 lines
6.5 KiB
C
/**
|
|
* \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 <omap_uart.h>
|
|
#include <dev/omap/omap44xx_uart3_dev.h>
|
|
#include <kernel.h>
|
|
#include <arm.h>
|
|
#include <paging_kernel_arch.h>
|
|
#include <arch/arm/platform.h>
|
|
#include <serial.h>
|
|
|
|
//
|
|
// 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;
|
|
}
|