1/** 2 * \file 3 * \brief ARM pl011 UART kernel-level driver. 4 */ 5 6/* 7 * Copyright (c) 2007, 2008, 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, Universitaetstrasse 6, CH-8092 Zurich. Attn: Systems Group. 13 */ 14 15#include <arch/arm/lpuart.h> 16#include <kernel.h> 17#include <paging_kernel_arch.h> 18#include <arch/arm/arm.h> 19#include <arch/arm/platform.h> 20#include <serial.h> 21#include <dev/lpuart_dev.h> 22 23static lpuart_t uarts[LPUART_MAX_PORTS]; 24 25// Mask all interrupts in the IMSC register 26#define INTERRUPTS_MASK 0 27 28#define MSG(format, ...) printk( LOG_NOTE, "lpuart: "format, ## __VA_ARGS__ ) 29 30static void lpuart_hw_init(lpuart_t *uart); 31 32/** 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. 36 */ 37errval_t serial_early_init(unsigned n) 38{ 39 assert(!paging_mmu_enabled()); 40 assert(n < serial_num_physical_ports); 41 42 lpuart_initialize(&uarts[n], 43 (mackerel_addr_t)local_phys_to_mem(platform_uart_base[n])); 44 45 // Make sure that the UART is enabled and transmitting - not all platforms 46 // do this for us. 47 lpuart_hw_init(&uarts[n]); 48 49 return SYS_ERR_OK; 50} 51 52/** 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. 56 */ 57errval_t serial_early_init_mmu_enabled(unsigned n) 58{ 59 assert(paging_mmu_enabled()); 60 assert(n < serial_num_physical_ports); 61 62 lpuart_initialize(&uarts[n], 63 (mackerel_addr_t)local_phys_to_mem(platform_uart_base[n])); 64 65 // Make sure that the UART is enabled and transmitting - not all platforms 66 // do this for us. 67 lpuart_hw_init(&uarts[n]); 68 69 return SYS_ERR_OK; 70} 71/* 72 * \brief Initialize a serial port. The MMU is turned on. 73 */ 74void lpuart_init(unsigned port, lvaddr_t base, bool hwinit) 75{ 76 assert(paging_mmu_enabled()); 77 assert(port < serial_num_physical_ports); 78 79 lpuart_t *u = &uarts[port]; 80 81 // [Re]initialize the Mackerel state for the UART 82 lpuart_initialize(u, (mackerel_addr_t) base); 83 84 if (hwinit) { 85 lpuart_hw_init(u); 86 } 87} 88 89static void lpuart_hw_init(lpuart_t *uart) 90{ 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); 96 97 //TODO: Figure out more advanced configuration (FIFO etc.) 98 99 // Set baudrate 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); 108 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); 114} 115 116/* 117 * \brief Put a character to the port 118 */ 119void serial_putchar(unsigned port, char c) 120{ 121 assert(port < LPUART_MAX_PORTS); 122 lpuart_t *u = &uarts[port]; 123 assert(u->base != 0); 124 125 while(lpuart_stat_tdre_rdf(u) == 0); 126 lpuart_txdata_wr(u,c); 127} 128 129/* 130 * \brief Read a character from a port 131 */ 132char serial_getchar(unsigned port) 133{ 134 assert(port < LPUART_MAX_PORTS); 135 lpuart_t *u = &uarts[port]; 136 assert(u->base != 0); 137 138 /* Wait for data. */ 139 while(lpuart_stat_rdrf_rdf(u) == 0); 140 141 return (char)lpuart_rxdata_buf_rdf(u); 142} 143