From ff265f9ad6505878a1b55d560ee697531fa33044 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonny=20Sv=C3=A4rd?= Date: Tue, 15 Dec 2020 16:02:41 +0100 Subject: Add basic UART drivers Add basic drivers for: - PL011 UART - CMSDK APB UART - dummy/stub UART Change-Id: I2f89874fba59044e6c7c084f8e1dc6faa9eb8d1b --- drivers/CMakeLists.txt | 13 +++ drivers/uart/CMakeLists.txt | 41 +++++++ drivers/uart/include/uart_stdout.h | 35 ++++++ drivers/uart/src/uart_cmsdk_apb.c | 135 +++++++++++++++++++++++ drivers/uart/src/uart_dummy.c | 36 ++++++ drivers/uart/src/uart_pl011.c | 220 +++++++++++++++++++++++++++++++++++++ drivers/uart/uart_config.h.in | 23 ++++ 7 files changed, 503 insertions(+) create mode 100644 drivers/uart/CMakeLists.txt create mode 100644 drivers/uart/include/uart_stdout.h create mode 100644 drivers/uart/src/uart_cmsdk_apb.c create mode 100644 drivers/uart/src/uart_dummy.c create mode 100644 drivers/uart/src/uart_pl011.c create mode 100644 drivers/uart/uart_config.h.in (limited to 'drivers') diff --git a/drivers/CMakeLists.txt b/drivers/CMakeLists.txt index c130a26..9feeeae 100644 --- a/drivers/CMakeLists.txt +++ b/drivers/CMakeLists.txt @@ -18,11 +18,18 @@ add_library(ethosu_drivers INTERFACE) +############################################################################# # Mailbox driver +############################################################################# add_subdirectory(mailbox) target_link_libraries(ethosu_drivers INTERFACE ethosu_mailbox) +############################################################################# # MHU drivers +############################################################################# +# NOTE: These are all built and linked from a CMake perspective. However the +# application code can instantiate one or more of the drivers. The +# one(s) not used will later be removed by the linker. add_subdirectory(mhu_v2) add_subdirectory(mhu_juno) add_subdirectory(mhu_dummy) @@ -30,3 +37,9 @@ target_link_libraries(ethosu_drivers INTERFACE ethosu_mhu_v2) target_link_libraries(ethosu_drivers INTERFACE ethosu_mhu_juno) target_link_libraries(ethosu_drivers INTERFACE ethosu_mhu_dummy) +############################################################################# +# UART drivers +############################################################################# +# NOTE: All UART drivers are built, however a platform application should +# link the appropriate driver target (see drivers/uart/CMakeLists.txt). +add_subdirectory(uart) diff --git a/drivers/uart/CMakeLists.txt b/drivers/uart/CMakeLists.txt new file mode 100644 index 0000000..1293bdc --- /dev/null +++ b/drivers/uart/CMakeLists.txt @@ -0,0 +1,41 @@ +# +# Copyright (c) 2019-2020 Arm Limited. All rights reserved. +# +# SPDX-License-Identifier: Apache-2.0 +# +# Licensed under the Apache License, Version 2.0 (the License); you may +# not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an AS IS BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +add_library(ethosu_uart_common INTERFACE) + +target_include_directories(ethosu_uart_common INTERFACE + include + ${CMAKE_CURRENT_BINARY_DIR}) + +# UART configuration (can be overriden from user project) +set(UART0_BASE "0xFFFFFFFF" CACHE STRING "UART base address") +set(UART0_BAUDRATE "115200" CACHE STRING "UART baudrate") +set(SYSTEM_CORE_CLOCK "25000000" CACHE STRING "System core clock (Hz)") + +# Generate UART configuration file +configure_file("${CMAKE_CURRENT_SOURCE_DIR}/uart_config.h.in" "${CMAKE_CURRENT_BINARY_DIR}/uart_config.h") + +# Drivers +add_library(ethosu_uart_cmsdk_apb STATIC src/uart_cmsdk_apb.c) +target_link_libraries(ethosu_uart_cmsdk_apb PUBLIC ethosu_uart_common) + +add_library(ethosu_uart_pl011 STATIC src/uart_pl011.c) +target_link_libraries(ethosu_uart_pl011 PUBLIC ethosu_uart_common) + +add_library(ethosu_uart_dummy STATIC src/uart_dummy.c) +target_link_libraries(ethosu_uart_dummy PUBLIC ethosu_uart_common) diff --git a/drivers/uart/include/uart_stdout.h b/drivers/uart/include/uart_stdout.h new file mode 100644 index 0000000..02f8e49 --- /dev/null +++ b/drivers/uart/include/uart_stdout.h @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2019-2020 Arm Limited. All rights reserved. + * + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the License); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an AS IS BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef _UART_STDOUT_H_ +#define _UART_STDOUT_H_ + +#if __cplusplus +extern "C" { +#endif + +void UartStdOutInit(void); +unsigned char UartPutc(unsigned char my_ch); +unsigned char UartGetc(void); +unsigned int GetLine(char *lp, unsigned int len); + +#if __cplusplus +} +#endif + +#endif diff --git a/drivers/uart/src/uart_cmsdk_apb.c b/drivers/uart/src/uart_cmsdk_apb.c new file mode 100644 index 0000000..2639ef5 --- /dev/null +++ b/drivers/uart/src/uart_cmsdk_apb.c @@ -0,0 +1,135 @@ +/* + * Copyright (c) 2019-2020 Arm Limited. All rights reserved. + * + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the License); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an AS IS BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* Basic CMSDK APB UART driver */ + +#include "uart_config.h" +#include "uart_stdout.h" +#include +#include + +#define CNTLQ 0x11 +#define CNTLS 0x13 +#define DEL 0x7F +#define BACKSPACE 0x08 +#define CR 0x0D +#define LF 0x0A +#define ESC 0x1B + +#define __IO volatile +#define __I volatile const +#define __O volatile + +typedef struct { + __IO uint32_t DATA; /* Offset: 0x000 (R/W) Data Register */ + __IO uint32_t STATE; /* Offset: 0x004 (R/W) Status Register */ + __IO uint32_t CTRL; /* Offset: 0x008 (R/W) Control Register */ + union { + __I uint32_t INTSTATUS; /* Offset: 0x00C (R/ ) Interrupt Status Register */ + __O uint32_t INTCLEAR; /* Offset: 0x00C ( /W) Interrupt Clear Register */ + }; + __IO uint32_t BAUDDIV; /* Offset: 0x010 (R/W) Baudrate Divider Register */ +} CMSDK_UART_TypeDef; + +#define CMSDK_UART0_BASE UART0_BASE +#define CMSDK_UART0 ((CMSDK_UART_TypeDef *)CMSDK_UART0_BASE) +#define CMSDK_UART0_BAUDRATE UART0_BAUDRATE + +void UartStdOutInit(void) { + CMSDK_UART0->BAUDDIV = SYSTEM_CORE_CLOCK / CMSDK_UART0_BAUDRATE; + + CMSDK_UART0->CTRL = ((1ul << 0) | /* TX enable */ + (1ul << 1)); /* RX enable */ +} + +// Output a character +unsigned char UartPutc(unsigned char my_ch) { + while ((CMSDK_UART0->STATE & 1)) + ; // Wait if Transmit Holding register is full + + if (my_ch == '\n') { + CMSDK_UART0->DATA = '\r'; + while ((CMSDK_UART0->STATE & 1)) + ; // Wait if Transmit Holding register is full + } + + CMSDK_UART0->DATA = my_ch; // write to transmit holding register + + return (my_ch); +} + +// Get a character +unsigned char UartGetc(void) { + unsigned char my_ch; + // unsigned int cnt; + + while ((CMSDK_UART0->STATE & 2) == 0) // Wait if Receive Holding register is empty + ; + + my_ch = CMSDK_UART0->DATA; + + // Convert CR to LF + if (my_ch == '\r') + my_ch = '\n'; + + return (my_ch); +} + +// Get line from terminal +unsigned int GetLine(char *lp, unsigned int len) { + unsigned int cnt = 0; + char c; + + do { + c = UartGetc(); + switch (c) { + case CNTLQ: /* ignore Control S/Q */ + case CNTLS: + break; + case BACKSPACE: + case DEL: + if (cnt == 0) { + break; + } + cnt--; /* decrement count */ + lp--; /* and line pointer */ + UartPutc(0x08); /* echo backspace */ + UartPutc(' '); + UartPutc(0x08); + fflush(stdout); + break; + case ESC: + case 0: + *lp = 0; /* ESC - stop editing line */ + return 0; + case CR: /* CR - done, stop editing line */ + *lp = c; + lp++; /* increment line pointer */ + cnt++; /* and count */ + c = LF; + default: + UartPutc(*lp = c); /* echo and store character */ + fflush(stdout); + lp++; /* increment line pointer */ + cnt++; /* and count */ + break; + } + } while (cnt < len - 2 && c != LF); /* check limit and CR */ + *lp = 0; /* mark end of string */ + return 1; +} diff --git a/drivers/uart/src/uart_dummy.c b/drivers/uart/src/uart_dummy.c new file mode 100644 index 0000000..ebe384b --- /dev/null +++ b/drivers/uart/src/uart_dummy.c @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2019-2020 Arm Limited. All rights reserved. + * + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the License); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an AS IS BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "uart_stdout.h" + +void UartStdOutInit(void) {} + +unsigned char UartPutc(unsigned char c) { + (void)c; + return 0; +} + +unsigned char UartGetc(void) { + return 0; +} + +unsigned int GetLine(char *lp, unsigned int len) { + (void)lp; + (void)len; + return 0; +} diff --git a/drivers/uart/src/uart_pl011.c b/drivers/uart/src/uart_pl011.c new file mode 100644 index 0000000..617ce5f --- /dev/null +++ b/drivers/uart/src/uart_pl011.c @@ -0,0 +1,220 @@ +/* + * Copyright (c) 2019-2020 Arm Limited. All rights reserved. + * + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the License); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an AS IS BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* Basic PL011 UART driver */ + +#include "uart_config.h" +#include "uart_stdout.h" +#include +#include + +#define CNTLQ 0x11 +#define CNTLS 0x13 +#define DEL 0x7F +#define BACKSPACE 0x08 +#define CR 0x0D +#define LF 0x0A +#define ESC 0x1B + +/*****************************************************************************/ +/* UART Control Register Locations */ +/*****************************************************************************/ +#define UART0_DR *((volatile uint32_t *)UART0_BASE) +#define UART0_RSR *((volatile uint32_t *)(UART0_BASE + 0x04)) +#define UART0_ECR *((volatile uint32_t *)(UART0_BASE + 0x04)) +#define UART0_LCRH *((volatile uint32_t *)(UART0_BASE + 0x2C)) +#define UART0_LCRM *((volatile uint32_t *)(UART0_BASE + 0x28)) +#define UART0_LCRL *((volatile uint32_t *)(UART0_BASE + 0x24)) +#define UART0_CR *((volatile uint32_t *)(UART0_BASE + 0x30)) +#define UART0_FR *((volatile uint32_t *)(UART0_BASE + 0x18)) +#define UART0_IIR *((volatile uint32_t *)(UART0_BASE + 0x1C)) +#define UART0_ICR *((volatile uint32_t *)(UART0_BASE + 0x44)) + +/*****************************************************************************/ +/* Received Status Register - RSR */ +/*****************************************************************************/ +#define RSR_OVERRUN_ERROR 0x08 +#define RSR_BREAK_ERROR 0x04 +#define RSR_PARITY_ERROR 0x02 +#define RSR_FRAMING_ERROR 0x01 + +/*****************************************************************************/ +/* Line Control High Byte Register - LCRH */ +/*****************************************************************************/ +#define LCRH_WORD_LENGTH_8 0x60 +#define LCRH_WORD_LENGTH_7 0x40 +#define LCRH_WORD_LENGTH_6 0x20 +#define LCRH_WORD_LENGTH_5 0x00 +#define LCRH_FIFO_ENABLED 0x10 +#define LCRH_2_STOP_BITS 0x08 +#define LCRH_EVEN_PARITY 0x04 +#define LCRH_PARITY_ENABLE 0x02 +#define LCRH_SEND_BREAK 0x01 + +/*****************************************************************************/ +/* Line Control Medium Byte Register - LCRM */ +/* This register specifies the high byte of the Baud rate divisor */ +/*****************************************************************************/ +#define LCRM_BAUD_460800 0x00 +#define LCRM_BAUD_230400 0x00 +#define LCRM_BAUD_115200 0x00 +#define LCRM_BAUD_76800 0x00 +#define LCRM_BAUD_57600 0x00 +#define LCRM_BAUD_38400 0x00 +#define LCRM_BAUD_19200 0x00 +#define LCRM_BAUD_14400 0x00 +#define LCRM_BAUD_9600 0x00 +#define LCRM_BAUD_2400 0x01 +#define LCRM_BAUD_1200 0x02 + +/*****************************************************************************/ +/* Line Control Low Byte Register - LCRL */ +/* This register specifies the low byte of the Baud rate divisor */ +/*****************************************************************************/ +#define LCRL_BAUD_460800 0x01 +#define LCRL_BAUD_230400 0x03 +#define LCRL_BAUD_115200 0x07 +#define LCRL_BAUD_76800 0x0B +#define LCRL_BAUD_57600 0x0F +#define LCRL_BAUD_38400 0xC +#define LCRL_BAUD_19200 0x2F +#define LCRL_BAUD_14400 0x3F +#define LCRL_BAUD_9600 0x5F +#define LCRL_BAUD_2400 0x7F +#define LCRL_BAUD_1200 0xFF + +/*****************************************************************************/ +/* Control Register - CR */ +/*****************************************************************************/ +#define CR_LOOP_BACK_EN 0x80 +#define CR_TIMEOUT_INT_EN 0x40 +#define CR_TX_INT_ENABLE 0x100 +#define CR_RX_INT_ENABLE 0x200 +#define CR_MODSTAT_INT_EN 0x08 +#define CR_UART_ENABLE 0x01 + +/*****************************************************************************/ +/* Flag Register - FR */ +/*****************************************************************************/ +#define FR_TX_FIFO_EMPTY 0x80 +#define FR_RX_FIFO_FULL 0x40 +#define FR_TX_FIFO_FULL 0x20 +#define FR_RX_FIFO_EMPTY 0x10 +#define FR_BUSY 0x08 +#define FR_CARRIER_DETECT 0x04 +#define FR_SET_READY 0x02 +#define FR_CLEAR_TO_SEND 0x01 + +/*****************************************************************************/ +/* Interrupt Identification Register - IIR */ +/*****************************************************************************/ +#define IIR_RX_TIME_OUT 0x08 +#define IIR_TX 0x04 +#define IIR_RX 0x02 +#define IIR_MODEM 0x01 + +void UartStdOutInit(void) { + // Disable the serial port while setting the baud rate and word length + UART0_CR = 0; + + // Clear the receive status register + UART0_ECR = 0; + + // Set the correct baud rate and word length + UART0_LCRL = LCRL_BAUD_115200; + UART0_LCRM = LCRM_BAUD_115200; + UART0_LCRH = LCRH_WORD_LENGTH_8; + + // Explicitly disable FIFO's for char mode + UART0_LCRH &= ~LCRH_FIFO_ENABLED; + + // Enable UART0 (and RX/TX) without interrupts + UART0_CR = CR_UART_ENABLE | CR_TX_INT_ENABLE | CR_RX_INT_ENABLE; +} + +unsigned char UartPutc(unsigned char ch) { + if (ch == '\n') { + (void)UartPutc('\r'); + } + while (UART0_FR & FR_TX_FIFO_FULL) + ; + UART0_DR = ch; + + return ch; +} + +unsigned char UartGetc(void) { + unsigned char c; + while (UART0_FR & FR_RX_FIFO_EMPTY) + ; + c = UART0_DR; + if (c == '\r') { + c = '\n'; + } + + return c; +} + +// Get line from terminal +unsigned int GetLine(char *lp, unsigned int len) { + unsigned int cnt = 0; + char c; + + do { + c = UartGetc(); + switch (c) { + case CNTLQ: /* ignore Control S/Q */ + case CNTLS: + break; + case BACKSPACE: + case DEL: + if (cnt == 0) { + break; + } + cnt--; /* decrement count */ + lp--; /* and line pointer */ + UartPutc(0x08); /* echo backspace */ + UartPutc(' '); + UartPutc(0x08); + fflush(stdout); + break; + case ESC: + case 0: + *lp = 0; /* ESC - stop editing line */ + return 0; + case CR: /* CR - done, stop editing line */ + *lp = c; + lp++; /* increment line pointer */ + cnt++; /* and count */ + c = LF; + UartPutc(*lp = c); /* echo and store character */ + fflush(stdout); + lp++; /* increment line pointer */ + cnt++; /* and count */ + break; + default: + UartPutc(*lp = c); /* echo and store character */ + fflush(stdout); + lp++; /* increment line pointer */ + cnt++; /* and count */ + break; + } + } while (cnt < len - 2 && c != LF); /* check limit and CR */ + *lp = 0; /* mark end of string */ + return 1; +} diff --git a/drivers/uart/uart_config.h.in b/drivers/uart/uart_config.h.in new file mode 100644 index 0000000..eb858fa --- /dev/null +++ b/drivers/uart/uart_config.h.in @@ -0,0 +1,23 @@ +/* + * Copyright (c) 2019-2020 Arm Limited. All rights reserved. + * + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the License); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an AS IS BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#define UART0_BASE (@UART0_BASE@) +#define UART0_BAUDRATE (@UART0_BAUDRATE@) +#define SYSTEM_CORE_CLOCK (@SYSTEM_CORE_CLOCK@) -- cgit v1.2.1