1/** 2 * \file 3 * \brief Kernel serial driver for the Xilinx Zynq7000-series UART 4 */ 5 6/* 7 * Copyright (c) 2016, 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, Universitaetstr 6, CH-8092 Zurich. Attn: Systems Group. 13 */ 14 15#include <kernel.h> 16 17#include <arm.h> 18#include <dev/zynq7/zynq_uart_dev.h> 19#include <paging_kernel_arch.h> 20#include <platform.h> 21#include <serial.h> 22#include <zynq_uart.h> 23#include <maps/zynq7_map.h> 24 25/* Serial console and debugger interfaces. */ 26static zynq_uart_t ports[ZYNQ_UART_MAX_PORTS]; 27 28static void zynq_uart_hw_init(zynq_uart_t *uart); 29 30#define MSG(port, format, ...) \ 31 printk( LOG_NOTE, "ZYNQ serial[%d]: "format, port, ## __VA_ARGS__ ) 32 33/* XXX - rename this. */ 34errval_t 35serial_early_init(unsigned port) { 36 assert(port < ZYNQ_UART_MAX_PORTS); 37 38 zynq_uart_initialize(&ports[port], (mackerel_addr_t)uart_base[port]); 39 40 /* Ensure the transmitter is enabled. */ 41 zynq_uart_CR_tx_dis_wrf(&ports[port], 0); 42 zynq_uart_CR_tx_en_wrf(&ports[port], 1); 43 44 return SYS_ERR_OK; 45} 46 47void 48zynq_uart_init(unsigned port, lvaddr_t base, bool initialize_hw) { 49 assert(port < ZYNQ_UART_MAX_PORTS); 50 zynq_uart_initialize(&ports[port], (mackerel_addr_t) base); 51 if(initialize_hw) zynq_uart_hw_init(&ports[port]); 52} 53 54/* 55 * Initialise Zynq UART 56 * Zynq TRM S19.3.1 57 */ 58static void 59zynq_uart_hw_init(zynq_uart_t *uart) { 60 /* Disable all interrupts. */ 61 zynq_uart_IDR_rawwr(uart, 0); 62 63 /* Clear all interrupts. */ 64 zynq_uart_ISR_rawwr(uart, 0xffffffff); 65 66 /* Trigger an interrupt on a single byte. */ 67 zynq_uart_RXWM_RTRIG_wrf(uart, 1); 68 69 /* Enable RX trigger interrupt. */ 70 zynq_uart_IER_rtrig_wrf(uart, 1); 71 72 /* Enable receiver. */ 73 zynq_uart_CR_rx_dis_wrf(uart, 0); 74 zynq_uart_CR_rx_en_wrf(uart, 1); 75} 76 77/** 78 * \brief Prints a single character to a serial port. 79 */ 80void 81serial_putchar(unsigned port, char c) { 82 assert(port <= ZYNQ_UART_MAX_PORTS); 83 zynq_uart_t *uart = &ports[port]; 84 85 /* Wait until FIFO can hold more characters. */ 86 while(zynq_uart_SR_TXFULL_rdf(uart)); 87 88 /* Write character. */ 89 zynq_uart_FIFO_FIFO_wrf(uart, c); 90} 91 92/** 93 * \brief Reads a single character from the default serial port. 94 */ 95char 96serial_getchar(unsigned port) { 97 assert(port <= ZYNQ_UART_MAX_PORTS); 98 zynq_uart_t *uart = &ports[port]; 99 100 /* Drain the FIFO. */ 101 char c= zynq_uart_FIFO_FIFO_rdf(uart); 102 while(!zynq_uart_SR_RXEMPTY_rdf(uart)) { 103 c= zynq_uart_FIFO_FIFO_rdf(uart); 104 } 105 106 /* Clear the RXTRIG interrupt. */ 107 zynq_uart_ISR_rtrig_wrf(uart, 1); 108 109 /* Return the character. */ 110 return c; 111} 112