diff options
Diffstat (limited to 'platform/ext/target/arm/musca_b1/sse_200/Native_Driver/uart_pl011_drv.c')
-rw-r--r-- | platform/ext/target/arm/musca_b1/sse_200/Native_Driver/uart_pl011_drv.c | 1019 |
1 files changed, 1019 insertions, 0 deletions
diff --git a/platform/ext/target/arm/musca_b1/sse_200/Native_Driver/uart_pl011_drv.c b/platform/ext/target/arm/musca_b1/sse_200/Native_Driver/uart_pl011_drv.c new file mode 100644 index 0000000000..01feaa4fdd --- /dev/null +++ b/platform/ext/target/arm/musca_b1/sse_200/Native_Driver/uart_pl011_drv.c @@ -0,0 +1,1019 @@ +/* + * Copyright (c) 2016-2018 Arm Limited + * + * 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 + * + * http://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_pl011_drv.h" + +#include <stddef.h> +#include "cmsis_compiler.h" + +#define FREQ_IRLPBAUD16_MIN (1420000u) /* 1.42 MHz */ +#define FREQ_IRLPBAUD16_MAX (2120000u) /* 2.12 MHz */ +#define SAMPLING_FACTOR (16u) +#define UART_PL011_FBRD_WIDTH (6u) + +/** + * \brief UART PL011 register map structure + */ +struct _uart_pl011_reg_map_t { + volatile uint32_t uartdr; /*!< Offset: 0x000 (R/W) Data register */ + union { + volatile uint32_t uartrsr; + /*!< Offset: 0x004 (R/ ) Receive status register */ + volatile uint32_t uartecr; + /*!< Offset: 0x004 ( /W) Error clear register */ + }; + volatile uint32_t reserved_0[4]; /*!< Offset: 0x008-0x014 Reserved */ + volatile uint32_t uartfr; /*!< Offset: 0x018 (R/ ) Flag register */ + volatile uint32_t reserved_1; /*!< Offset: 0x01C Reserved */ + volatile uint32_t uartilpr; + /*!< Offset: 0x020 (R/W) IrDA low-power counter register */ + volatile uint32_t uartibrd; + /*!< Offset: 0x024 (R/W) Integer baud rate register */ + volatile uint32_t uartfbrd; + /*!< Offset: 0x028 (R/W) Fractional baud rate register */ + volatile uint32_t uartlcr_h; + /*!< Offset: 0x02C (R/W) Line control register */ + volatile uint32_t uartcr; + /*!< Offset: 0x030 (R/W) Control register */ + volatile uint32_t uartifls; + /*!< Offset: 0x034 (R/W) Interrupt FIFO level select register */ + volatile uint32_t uartimsc; + /*!< Offset: 0x038 (R/W) Interrupt mask set/clear register */ + volatile uint32_t uartris; + /*!< Offset: 0x03C (R/ ) Raw interrupt status register */ + volatile uint32_t uartmis; + /*!< Offset: 0x040 (R/ ) Masked interrupt status register */ + volatile uint32_t uarticr; + /*!< Offset: 0x044 ( /W) Interrupt clear register */ + volatile uint32_t uartdmacr; + /*!< Offset: 0x048 (R/W) DMA control register */ + volatile uint32_t reserved_2[13]; /*!< Offset: 0x04C-0x07C Reserved */ + volatile uint32_t reserved_3[4]; + /*!< Offset: 0x080-0x08C Reserved for test purposes */ + volatile uint32_t reserved_4[976]; /*!< Offset: 0x090-0xFCC Reserved */ + volatile uint32_t reserved_5[4]; + /*!< Offset: 0xFD0-0xFDC Reserved for future ID expansion */ + volatile uint32_t uartperiphid0; + /*!< Offset: 0xFE0 (R/ ) UARTPeriphID0 register */ + volatile uint32_t uartperiphid1; + /*!< Offset: 0xFE4 (R/ ) UARTPeriphID1 register */ + volatile uint32_t uartperiphid2; + /*!< Offset: 0xFE8 (R/ ) UARTPeriphID2 register */ + volatile uint32_t uartperiphid3; + /*!< Offset: 0xFEC (R/ ) UARTPeriphID3 register */ + volatile uint32_t uartpcellid0; + /*!< Offset: 0xFF0 (R/ ) UARTPCellID0 register */ + volatile uint32_t uartpcellid1; + /*!< Offset: 0xFF4 (R/ ) UARTPCellID1 register */ + volatile uint32_t uartpcellid2; + /*!< Offset: 0xFF8 (R/ ) UARTPCellID2 register */ + volatile uint32_t uartpcellid3; + /*!< Offset: 0xFFC (R/ ) UARTPCellID3 register */ +}; + +#define UART_PL011_UARTFR_CTS_MASK ( \ + 0x1u<<UART_PL011_UARTFR_CTS_OFF) +#define UART_PL011_UARTFR_DSR_MASK ( \ + 0x1u<<UART_PL011_UARTFR_DSR_OFF) +#define UART_PL011_UARTFR_DCD_MASK ( \ + 0x1u<<UART_PL011_UARTFR_DCD_OFF) +#define UART_PL011_UARTFR_BUSYBIT ( \ + 0x1u<<UART_PL011_UARTFR_BUSYBIT_OFF) +#define UART_PL011_UARTFR_RX_FIFO_EMPTY ( \ + 0x1u<<UART_PL011_UARTFR_RX_FIFO_EMPTY_OFF) +#define UART_PL011_UARTFR_TX_FIFO_FULL ( \ + 0x1u<<UART_PL011_UARTFR_TX_FIFO_FULL_OFF) +#define UART_PL011_UARTFR_RI_MASK ( \ + 0x1u<<UART_PL011_UARTFR_RI_OFF) + +#define UART_PL011_UARTLCR_H_BRK_MASK ( \ + 0x1u<<UART_PL011_UARTLCR_H_BRK_OFF) +#define UART_PL011_UARTLCR_H_PARITY_MASK ( \ + 0x1u<<UART_PL011_UARTLCR_H_PEN_OFF \ + | 0x1u<<UART_PL011_UARTLCR_H_EPS_OFF \ + | 0x1u<<UART_PL011_UARTLCR_H_SPS_OFF) +#define UART_PL011_UARTLCR_H_STOPBIT_MASK ( \ + 0x1u<<UART_PL011_UARTLCR_H_STP2_OFF) +#define UART_PL011_UARTLCR_H_FEN_MASK ( \ + 0x1u<<UART_PL011_UARTLCR_H_FEN_OFF) +#define UART_PL011_UARTLCR_H_WLEN_MASK ( \ + 0x3u<<UART_PL011_UARTLCR_H_WLEN_OFF) +#define UART_PL011_FORMAT_MASK ( \ + UART_PL011_UARTLCR_H_PARITY_MASK \ + | UART_PL011_UARTLCR_H_STOPBIT_MASK \ + | UART_PL011_UARTLCR_H_WLEN_MASK) + +#define UART_PL011_UARTCR_EN_MASK ( \ + 0x1u<<UART_PL011_UARTCR_UARTEN_OFF) +#define UART_PL011_UARTCR_SIREN_MASK ( \ + 0x1u<<UART_PL011_UARTCR_SIREN_OFF) +#define UART_PL011_UARTCR_SIRLP_MASK ( \ + 0x1u<<UART_PL011_UARTCR_SIRLP_OFF) +#define UART_PL011_UARTCR_LBE_MASK ( \ + 0x1u<<UART_PL011_UARTCR_LBE_OFF) +#define UART_PL011_UARTCR_TX_EN_MASK ( \ + 0x1u<<UART_PL011_UARTCR_TXE_OFF) +#define UART_PL011_UARTCR_RX_EN_MASK ( \ + 0x1u<<UART_PL011_UARTCR_RXE_OFF) +#define UART_PL011_UARTCR_DTR_MASK ( \ + 0x1u<<UART_PL011_UARTCR_DTR_OFF) +#define UART_PL011_UARTCR_RTS_MASK ( \ + 0x1u<<UART_PL011_UARTCR_RTS_OFF) +#define UART_PL011_UARTCR_OUT1_MASK ( \ + 0x1u<<UART_PL011_UARTCR_OUT1_OFF) +#define UART_PL011_UARTCR_OUT2_MASK ( \ + 0x1u<<UART_PL011_UARTCR_OUT2_OFF) +#define UART_PL011_UARTCR_RTSE_MASK ( \ + 0x1u<<UART_PL011_UARTCR_RTSE_OFF) +#define UART_PL011_UARTCR_CTSE_MASK ( \ + 0x1u<<UART_PL011_UARTCR_CTSE_OFF) + +#define UART_PL011_UARTIFLS_TX_FIFO_LVL_MASK ( \ + 0x7u<<UART_PL011_UARTIFLS_TX_OFF) +#define UART_PL011_UARTIFLS_RX_FIFO_LVL_MASK ( \ + 0x7u<<UART_PL011_UARTIFLS_RX_OFF) + +#define UART_PL011_UARTDMACR_RX_MASK ( \ + 0x1u<<UART_PL011_UARTDMACR_RXEN_OFF \ + | 0x1u<<UART_PL011_UARTDMACR_ON_ERR_OFF) +#define UART_PL011_UARTDMACR_TX_MASK ( \ + 0x1u<<UART_PL011_UARTDMACR_TXEN_OFF) + +/* Default register values of UART PL011 */ +#define UART_PL011_DATA_REG_RESET_VALUE (0x0u) +#define UART_PL011_ECR_REG_CLEAR_VALUE (0xFFu) +#define UART_PL011_ILPR_REG_RESET_VALUE (0x0u) +#define UART_PL011_IBRD_REG_RESET_VALUE (0x0u) +#define UART_PL011_FBRD_REG_RESET_VALUE (0x0u) +#define UART_PL011_LCR_H_REG_RESET_VALUE (0x0u) +#define UART_PL011_CR_REG_RESET_VALUE (0x0300u) +#define UART_PL011_IFLS_REG_RESET_VALUE (0x12u) +#define UART_PL011_IMSC_REG_RESET_VALUE (0x0u) +#define UART_PL011_ICR_REG_CLEAR_VALUE (0x7FFu) +#define UART_PL011_DMACR_REG_RESET_VALUE (0x0u) + +static void _uart_pl011_enable(struct _uart_pl011_reg_map_t* p_uart) +{ + p_uart->uartcr |= UART_PL011_UARTCR_EN_MASK; +} + +static void _uart_pl011_disable(struct _uart_pl011_reg_map_t* p_uart) +{ + p_uart->uartcr &= ~UART_PL011_UARTCR_EN_MASK; +} + +static bool _uart_pl011_is_enabled(struct _uart_pl011_reg_map_t* p_uart) +{ + return (bool)(p_uart->uartcr & UART_PL011_UARTCR_EN_MASK); +} + +static void _uart_pl011_enable_fifo(struct _uart_pl011_reg_map_t* p_uart) +{ + p_uart->uartlcr_h |= UART_PL011_UARTLCR_H_FEN_MASK; +} + +static void _uart_pl011_disable_fifo(struct _uart_pl011_reg_map_t* p_uart) +{ + p_uart->uartlcr_h &= ~UART_PL011_UARTLCR_H_FEN_MASK; +} + +static bool _uart_pl011_is_fifo_enabled(struct _uart_pl011_reg_map_t* p_uart) +{ + return (bool)(p_uart->uartlcr_h & UART_PL011_UARTLCR_H_FEN_MASK); +} + +static bool _uart_pl011_is_busy(struct _uart_pl011_reg_map_t* p_uart) +{ + return (bool)(p_uart->uartfr & UART_PL011_UARTFR_BUSYBIT); +} + +static enum uart_pl011_error_t _uart_pl011_set_baudrate( + struct _uart_pl011_reg_map_t* p_uart, + uint32_t clk, uint32_t baudrate) +{ + /* Avoiding float calculations, bauddiv is left shifted by 6 */ + uint64_t bauddiv = (((uint64_t)clk)<<UART_PL011_FBRD_WIDTH) + /(SAMPLING_FACTOR*baudrate); + + /* Valid bauddiv value + * uart_clk (min) >= 16 x baud_rate (max) + * uart_clk (max) <= 16 x 65535 x baud_rate (min) + */ + if((bauddiv < (1u<<UART_PL011_FBRD_WIDTH)) + || (bauddiv > (65535u<<UART_PL011_FBRD_WIDTH))) { + return UART_PL011_ERR_INVALID_BAUD; + } + + p_uart->uartibrd = (uint32_t)(bauddiv >> UART_PL011_FBRD_WIDTH); + p_uart->uartfbrd = (uint32_t)(bauddiv & + ((1u << UART_PL011_FBRD_WIDTH) - 1u)); + + __DMB(); + + /* In order to internally update the contents of uartibrd or uartfbrd, a + * uartlcr_h write must always be performed at the end + * ARM DDI 0183F, Pg 3-13 + */ + p_uart->uartlcr_h = p_uart->uartlcr_h; + + return UART_PL011_ERR_NONE; +} + +static void _uart_pl011_set_format(struct _uart_pl011_reg_map_t* p_uart, + enum uart_pl011_wlen_t word_len, + enum uart_pl011_parity_t parity, + enum uart_pl011_stopbit_t stop_bits) +{ + uint32_t ctrl_reg = p_uart->uartlcr_h & ~(UART_PL011_FORMAT_MASK); + + /* Making sure other bit are not changed */ + word_len &= UART_PL011_UARTLCR_H_WLEN_MASK; + parity &= UART_PL011_UARTLCR_H_PARITY_MASK; + stop_bits &= UART_PL011_UARTLCR_H_STOPBIT_MASK; + + p_uart->uartlcr_h = ctrl_reg | word_len | parity | stop_bits; + +} + +static void _uart_pl011_set_cr_bit(struct _uart_pl011_reg_map_t* p_uart, + uint32_t mask) +{ + bool uart_enabled = _uart_pl011_is_enabled(p_uart); + bool fifo_enabled = _uart_pl011_is_fifo_enabled(p_uart); + + /* UART must be disabled before any Control Register or + * Line Control Register are reprogrammed */ + _uart_pl011_disable(p_uart); + + /* Flush the transmit FIFO by disabling bit 4 (FEN) in + * the line control register (UARTCLR_H) */ + _uart_pl011_disable_fifo(p_uart); + + p_uart->uartcr |= (mask); + + /* Enabling the FIFOs if previously enabled */ + if(fifo_enabled) { + _uart_pl011_enable_fifo(p_uart); + } + + /* Enabling the UART if previously enabled */ + if(uart_enabled) { + _uart_pl011_enable(p_uart); + } +} + +static void _uart_pl011_clear_cr_bit(struct _uart_pl011_reg_map_t* p_uart, + uint32_t mask) +{ + bool uart_enabled = _uart_pl011_is_enabled(p_uart); + bool fifo_enabled = _uart_pl011_is_fifo_enabled(p_uart); + + /* UART must be disabled before any Control Register or + * Line Control Register are reprogrammed */ + _uart_pl011_disable(p_uart); + + /* Flush the transmit FIFO by disabling bit 4 (FEN) in + * the line control register (UARTCLR_H) */ + _uart_pl011_disable_fifo(p_uart); + + p_uart->uartcr &= ~(mask); + + /* Enabling the FIFOs if previously enabled */ + if(fifo_enabled) { + _uart_pl011_enable_fifo(p_uart); + } + + /* Enabling the UART if previously enabled */ + if(uart_enabled) { + _uart_pl011_enable(p_uart); + } +} + +static void _uart_pl011_set_lcr_h_bit(struct _uart_pl011_reg_map_t* p_uart, + uint32_t mask) +{ + bool uart_enabled = _uart_pl011_is_enabled(p_uart); + + /* UART must be disabled before any Control Register or + * Line Control Register are reprogrammed */ + _uart_pl011_disable(p_uart); + + p_uart->uartlcr_h |= (mask); + + /* Enabling the UART if previously enabled */ + if(uart_enabled) { + _uart_pl011_enable(p_uart); + } +} + +static void _uart_pl011_clear_lcr_h_bit(struct _uart_pl011_reg_map_t* p_uart, + uint32_t mask) +{ + bool uart_enabled = _uart_pl011_is_enabled(p_uart); + + /* UART must be disabled before any Control Register or + * Line Control Register are reprogrammed */ + _uart_pl011_disable(p_uart); + + p_uart->uartlcr_h &= ~(mask); + + /* Enabling the UART if previously enabled */ + if(uart_enabled) { + _uart_pl011_enable(p_uart); + } +} + +static void _uart_pl011_reset_regs(struct _uart_pl011_reg_map_t* p_uart) +{ + /* Restore the default value of UART registers, the registers which + * are not listed below are Read-Only */ + + /* Will disable the UART */ + p_uart->uartcr = UART_PL011_CR_REG_RESET_VALUE; + p_uart->uartdr = UART_PL011_DATA_REG_RESET_VALUE; + /* Clear all the errors */ + p_uart->uartecr = UART_PL011_ECR_REG_CLEAR_VALUE; + p_uart->uartilpr = UART_PL011_ILPR_REG_RESET_VALUE; + p_uart->uartibrd = UART_PL011_IBRD_REG_RESET_VALUE; + p_uart->uartfbrd = UART_PL011_FBRD_REG_RESET_VALUE; + p_uart->uartlcr_h = UART_PL011_LCR_H_REG_RESET_VALUE; + p_uart->uartifls = UART_PL011_IFLS_REG_RESET_VALUE; + p_uart->uartimsc = UART_PL011_IMSC_REG_RESET_VALUE; + /* Clear all the interrupts */ + p_uart->uarticr = UART_PL011_ICR_REG_CLEAR_VALUE; + p_uart->uartdmacr = UART_PL011_DMACR_REG_RESET_VALUE; +} + +enum uart_pl011_error_t uart_pl011_init(struct uart_pl011_dev_t* dev, + uint32_t uart_clk) +{ + enum uart_pl011_error_t err; + + struct _uart_pl011_reg_map_t* p_uart = + (struct _uart_pl011_reg_map_t*)dev->cfg->base; + + uint32_t def_baud = dev->cfg->def_baudrate; + + if(uart_clk == 0) { + return UART_PL011_ERR_INVALID_ARG; + } + + if(def_baud == 0) { + return UART_PL011_ERR_INVALID_BAUD; + } + + /* Updating the system clock */ + dev->data->uart_clk = uart_clk; + + /* Setting the default baudrate */ + err = _uart_pl011_set_baudrate(p_uart, uart_clk, def_baud); + + if(err != UART_PL011_ERR_NONE) { + return err; + } + + /* Setting the default character format */ + _uart_pl011_set_format(p_uart, dev->cfg->def_wlen, + dev->cfg->def_parity, + dev->cfg->def_stopbit); + + /* Enabling the FIFOs */ + _uart_pl011_enable_fifo(p_uart); + + dev->data->state = UART_PL011_INITIALIZED; + + return UART_PL011_ERR_NONE; +} + +void uart_pl011_uninit(struct uart_pl011_dev_t* dev) +{ + struct _uart_pl011_reg_map_t* p_uart = + (struct _uart_pl011_reg_map_t*)dev->cfg->base; + + while(_uart_pl011_is_busy(p_uart)); + + /* Disable and restore the default configuration of the peripheral */ + _uart_pl011_reset_regs(p_uart); + + dev->data->state = UART_PL011_UNINITIALIZED; + + return; +} + +enum uart_pl011_state_t uart_pl011_get_state(struct uart_pl011_dev_t* dev) +{ + return dev->data->state; +} + +enum uart_pl011_error_t uart_pl011_set_baudrate( + struct uart_pl011_dev_t* dev, uint32_t baudrate) +{ + enum uart_pl011_error_t err = UART_PL011_ERR_NONE; + + struct _uart_pl011_reg_map_t* p_uart = + (struct _uart_pl011_reg_map_t*)dev->cfg->base; + + bool uart_enabled = _uart_pl011_is_enabled(p_uart); + + if(uart_pl011_get_state(dev) != UART_PL011_INITIALIZED) { + return UART_PL011_ERR_NOT_INIT; + } + + if(baudrate == 0) { + return UART_PL011_ERR_INVALID_BAUD; + } + + /* UART must be disabled before any Control Register or + * Line Control Register are reprogrammed */ + _uart_pl011_disable(p_uart); + + /* If baudrate is not valid ie UART_PL011_ERR_NONE is not returned then + * the UART will continue to function at the old baudrate */ + err = _uart_pl011_set_baudrate(p_uart, dev->data->uart_clk, baudrate); + + if(err == UART_PL011_ERR_NONE) { + dev->data->baudrate = baudrate; + } + + if(uart_enabled) { + _uart_pl011_enable(p_uart); + } + + return err; +} + +uint32_t uart_pl011_get_baudrate(struct uart_pl011_dev_t* dev) +{ + return dev->data->baudrate; +} + +void uart_pl011_enable_intr(struct uart_pl011_dev_t* dev, + enum uart_pl011_intr_t mask) +{ + struct _uart_pl011_reg_map_t* p_uart = + (struct _uart_pl011_reg_map_t*)dev->cfg->base; + + p_uart->uartimsc |= (uint32_t)(mask); + + return; +} + +void uart_pl011_disable_intr(struct uart_pl011_dev_t* dev, + enum uart_pl011_intr_t mask) +{ + struct _uart_pl011_reg_map_t* p_uart = + (struct _uart_pl011_reg_map_t*)dev->cfg->base; + + p_uart->uartimsc &= (uint32_t)(~mask); + + return; +} + +void uart_pl011_clear_intr(struct uart_pl011_dev_t* dev, + enum uart_pl011_intr_t mask) +{ + struct _uart_pl011_reg_map_t* p_uart = + (struct _uart_pl011_reg_map_t*)dev->cfg->base; + + p_uart->uarticr = (uint32_t)mask; + + return; +} + + +enum uart_pl011_intr_t uart_pl011_get_masked_intr_status( + struct uart_pl011_dev_t* dev) +{ + struct _uart_pl011_reg_map_t* p_uart = + (struct _uart_pl011_reg_map_t*)dev->cfg->base; + + return (enum uart_pl011_intr_t)(p_uart->uartmis); + +} + +enum uart_pl011_intr_t uart_pl011_get_raw_intr_status( + struct uart_pl011_dev_t* dev) +{ + struct _uart_pl011_reg_map_t* p_uart = + (struct _uart_pl011_reg_map_t*)dev->cfg->base; + + return (enum uart_pl011_intr_t)(p_uart->uartris); +} + +void uart_pl011_set_rx_fifo_lvl(struct uart_pl011_dev_t* dev, + enum uart_pl011_rx_fifo_lvl_t rx_lvl) +{ + uint32_t fifo_lvl; + + struct _uart_pl011_reg_map_t* p_uart = + (struct _uart_pl011_reg_map_t*)dev->cfg->base; + + /* Check if rx_lvl have valid values */ + rx_lvl &= UART_PL011_UARTIFLS_RX_FIFO_LVL_MASK; + + fifo_lvl = p_uart->uartifls + & ~(UART_PL011_UARTIFLS_RX_FIFO_LVL_MASK); + p_uart->uartifls = fifo_lvl | rx_lvl; + + return; +} + +void uart_pl011_set_tx_fifo_lvl(struct uart_pl011_dev_t* dev, + enum uart_pl011_tx_fifo_lvl_t tx_lvl) +{ + uint32_t fifo_lvl; + + struct _uart_pl011_reg_map_t* p_uart = + (struct _uart_pl011_reg_map_t*)dev->cfg->base; + /* Check if tx_lvl have valid values */ + tx_lvl &= UART_PL011_UARTIFLS_TX_FIFO_LVL_MASK; + + fifo_lvl = p_uart->uartifls + & ~(UART_PL011_UARTIFLS_TX_FIFO_LVL_MASK); + p_uart->uartifls = fifo_lvl | tx_lvl; + + return; +} + +void uart_pl011_set_tx_dma(struct uart_pl011_dev_t* dev, + enum uart_pl011_tx_dma_t enable) +{ + uint32_t dma_cr; + + struct _uart_pl011_reg_map_t* p_uart = + (struct _uart_pl011_reg_map_t*)dev->cfg->base; + + enable &= UART_PL011_UARTDMACR_TX_MASK; + + dma_cr = p_uart->uartdmacr + & ~(UART_PL011_UARTDMACR_TX_MASK); + + p_uart->uartdmacr = dma_cr | enable; + + return; +} + +void uart_pl011_set_rx_dma(struct uart_pl011_dev_t* dev, + enum uart_pl011_rx_dma_t enable) +{ + uint32_t dma_cr; + + struct _uart_pl011_reg_map_t* p_uart = + (struct _uart_pl011_reg_map_t*)dev->cfg->base; + + enable &= UART_PL011_UARTDMACR_RX_MASK; + + dma_cr = p_uart->uartdmacr + & ~(UART_PL011_UARTDMACR_RX_MASK); + + p_uart->uartdmacr = dma_cr | enable; + + return; +} + +bool uart_pl011_is_readable(struct uart_pl011_dev_t* dev) +{ + struct _uart_pl011_reg_map_t* p_uart = + (struct _uart_pl011_reg_map_t*)dev->cfg->base; + + if( (uart_pl011_get_state(dev) == UART_PL011_INITIALIZED) && + /* UART is initialized */ + (p_uart->uartcr & UART_PL011_UARTCR_EN_MASK) && + /* UART is enabled */ + (p_uart->uartcr & UART_PL011_UARTCR_RX_EN_MASK) && + /* Receive is enabled */ + ((p_uart->uartfr & UART_PL011_UARTFR_RX_FIFO_EMPTY) == 0)) { + /* Receive Fifo is not empty */ + return true; + } + + return false; + +} + +enum uart_pl011_error_t uart_pl011_read( + struct uart_pl011_dev_t* dev, uint8_t* byte) +{ + struct _uart_pl011_reg_map_t* p_uart = + (struct _uart_pl011_reg_map_t*)dev->cfg->base; + + *byte = p_uart->uartdr; + + return (enum uart_pl011_error_t)(p_uart->uartrsr + & UART_PL011_RX_ERR_MASK); +} + +bool uart_pl011_is_writable(struct uart_pl011_dev_t* dev) +{ + struct _uart_pl011_reg_map_t* p_uart = + (struct _uart_pl011_reg_map_t*)dev->cfg->base; + + if( (uart_pl011_get_state(dev) == UART_PL011_INITIALIZED) && + /* UART is initialized */ + (p_uart->uartcr & UART_PL011_UARTCR_EN_MASK) && + /* UART is enabled */ + (p_uart->uartcr & UART_PL011_UARTCR_TX_EN_MASK) && + /* Transmit is enabled */ + ((p_uart->uartfr & UART_PL011_UARTFR_TX_FIFO_FULL) == 0)) { + /* Transmit Fifo is not full */ + return true; + } + return false; + +} + +void uart_pl011_write(struct uart_pl011_dev_t* dev, uint8_t byte) +{ + struct _uart_pl011_reg_map_t* p_uart = + (struct _uart_pl011_reg_map_t*)dev->cfg->base; + + p_uart->uartdr = byte; + + return; +} + +enum uart_pl011_error_t uart_pl011_set_format(struct uart_pl011_dev_t* dev, + enum uart_pl011_wlen_t word_len, + enum uart_pl011_parity_t parity, + enum uart_pl011_stopbit_t stop_bits) +{ + struct _uart_pl011_reg_map_t* p_uart = + (struct _uart_pl011_reg_map_t*)dev->cfg->base; + + bool uart_enabled = _uart_pl011_is_enabled(p_uart); + + if(uart_pl011_get_state(dev) != UART_PL011_INITIALIZED) { + return UART_PL011_ERR_NOT_INIT; + } + + /* UART must be disabled before any Control Register or + * Line Control Register are reprogrammed */ + _uart_pl011_disable(p_uart); + + _uart_pl011_set_format(p_uart, word_len, parity, stop_bits); + + /* Enabling the UART if previously enabled */ + if(uart_enabled) { + _uart_pl011_enable(p_uart); + } + + return UART_PL011_ERR_NONE; +} + +void uart_pl011_enable_fifo(struct uart_pl011_dev_t* dev) +{ + struct _uart_pl011_reg_map_t* p_uart = + (struct _uart_pl011_reg_map_t*)dev->cfg->base; + + _uart_pl011_set_lcr_h_bit(p_uart, UART_PL011_UARTLCR_H_FEN_MASK); + + return; +} + +void uart_pl011_disable_fifo(struct uart_pl011_dev_t* dev) +{ + struct _uart_pl011_reg_map_t* p_uart = + (struct _uart_pl011_reg_map_t*)dev->cfg->base; + + _uart_pl011_clear_lcr_h_bit(p_uart, UART_PL011_UARTLCR_H_FEN_MASK); + + return; +} + +void uart_pl011_enable_break(struct uart_pl011_dev_t* dev) +{ + struct _uart_pl011_reg_map_t* p_uart = + (struct _uart_pl011_reg_map_t*)dev->cfg->base; + + _uart_pl011_set_lcr_h_bit(p_uart, UART_PL011_UARTLCR_H_BRK_MASK); + + return; +} + +void uart_pl011_disable_break(struct uart_pl011_dev_t* dev) +{ + struct _uart_pl011_reg_map_t* p_uart = + (struct _uart_pl011_reg_map_t*)dev->cfg->base; + + _uart_pl011_clear_lcr_h_bit(p_uart, UART_PL011_UARTLCR_H_BRK_MASK); + + return; +} + +void uart_pl011_enable_cts_flowcontrol(struct uart_pl011_dev_t* dev) +{ + struct _uart_pl011_reg_map_t* p_uart = + (struct _uart_pl011_reg_map_t*)dev->cfg->base; + + _uart_pl011_set_cr_bit(p_uart, UART_PL011_UARTCR_CTSE_MASK); + + return; +} + +void uart_pl011_disable_cts_flowcontrol(struct uart_pl011_dev_t* dev) +{ + struct _uart_pl011_reg_map_t* p_uart = + (struct _uart_pl011_reg_map_t*)dev->cfg->base; + + _uart_pl011_clear_cr_bit(p_uart, UART_PL011_UARTCR_CTSE_MASK); + + return; +} + +void uart_pl011_enable_rts_flowcontrol(struct uart_pl011_dev_t* dev) +{ + struct _uart_pl011_reg_map_t* p_uart = + (struct _uart_pl011_reg_map_t*)dev->cfg->base; + + _uart_pl011_set_cr_bit(p_uart, UART_PL011_UARTCR_RTSE_MASK); + + return; +} + +void uart_pl011_disable_rts_flowcontrol(struct uart_pl011_dev_t* dev) +{ + struct _uart_pl011_reg_map_t* p_uart = + (struct _uart_pl011_reg_map_t*)dev->cfg->base; + + _uart_pl011_clear_cr_bit(p_uart, UART_PL011_UARTCR_RTSE_MASK); + + return; +} + +void uart_pl011_enable_ri(struct uart_pl011_dev_t* dev) +{ + struct _uart_pl011_reg_map_t* p_uart = + (struct _uart_pl011_reg_map_t*)dev->cfg->base; + + _uart_pl011_set_cr_bit(p_uart, UART_PL011_UARTCR_OUT2_MASK); + + return; +} + +void uart_pl011_disable_ri(struct uart_pl011_dev_t* dev) +{ + struct _uart_pl011_reg_map_t* p_uart = + (struct _uart_pl011_reg_map_t*)dev->cfg->base; + + _uart_pl011_clear_cr_bit(p_uart, UART_PL011_UARTCR_OUT2_MASK); + + return; +} + +void uart_pl011_enable_dcd(struct uart_pl011_dev_t* dev) +{ + struct _uart_pl011_reg_map_t* p_uart = + (struct _uart_pl011_reg_map_t*)dev->cfg->base; + + _uart_pl011_set_cr_bit(p_uart, UART_PL011_UARTCR_OUT1_MASK); + + return; +} + +void uart_pl011_disable_dcd(struct uart_pl011_dev_t* dev) +{ + struct _uart_pl011_reg_map_t* p_uart = + (struct _uart_pl011_reg_map_t*)dev->cfg->base; + + _uart_pl011_clear_cr_bit(p_uart, UART_PL011_UARTCR_OUT1_MASK); + + return; +} + +void uart_pl011_set_rts(struct uart_pl011_dev_t* dev) +{ + struct _uart_pl011_reg_map_t* p_uart = + (struct _uart_pl011_reg_map_t*)dev->cfg->base; + + _uart_pl011_set_cr_bit(p_uart, UART_PL011_UARTCR_RTS_MASK); + + return; +} + +void uart_pl011_clear_rts(struct uart_pl011_dev_t* dev) +{ + struct _uart_pl011_reg_map_t* p_uart = + (struct _uart_pl011_reg_map_t*)dev->cfg->base; + + _uart_pl011_clear_cr_bit(p_uart, UART_PL011_UARTCR_RTS_MASK); + + return; +} + +void uart_pl011_set_dtr(struct uart_pl011_dev_t* dev) +{ + struct _uart_pl011_reg_map_t* p_uart = + (struct _uart_pl011_reg_map_t*)dev->cfg->base; + + _uart_pl011_set_cr_bit(p_uart, UART_PL011_UARTCR_DTR_MASK); + + return; +} + +void uart_pl011_clear_dtr(struct uart_pl011_dev_t* dev) +{ + struct _uart_pl011_reg_map_t* p_uart = + (struct _uart_pl011_reg_map_t*)dev->cfg->base; + + _uart_pl011_clear_cr_bit(p_uart, UART_PL011_UARTCR_DTR_MASK); + + return; +} + +void uart_pl011_enable_receive(struct uart_pl011_dev_t* dev) +{ + struct _uart_pl011_reg_map_t* p_uart = + (struct _uart_pl011_reg_map_t*)dev->cfg->base; + + _uart_pl011_set_cr_bit(p_uart, UART_PL011_UARTCR_RX_EN_MASK); + + return; +} + +void uart_pl011_disable_receive(struct uart_pl011_dev_t* dev) +{ + struct _uart_pl011_reg_map_t* p_uart = + (struct _uart_pl011_reg_map_t*)dev->cfg->base; + + _uart_pl011_clear_cr_bit(p_uart, UART_PL011_UARTCR_RX_EN_MASK); + + return; +} + +void uart_pl011_enable_transmit(struct uart_pl011_dev_t* dev) +{ + struct _uart_pl011_reg_map_t* p_uart = + (struct _uart_pl011_reg_map_t*)dev->cfg->base; + + _uart_pl011_set_cr_bit(p_uart, UART_PL011_UARTCR_TX_EN_MASK); + + return; +} + +void uart_pl011_disable_transmit(struct uart_pl011_dev_t* dev) +{ + struct _uart_pl011_reg_map_t* p_uart = + (struct _uart_pl011_reg_map_t*)dev->cfg->base; + + _uart_pl011_clear_cr_bit(p_uart, UART_PL011_UARTCR_TX_EN_MASK); + + return; +} + +void uart_pl011_set_loopback(struct uart_pl011_dev_t* dev) +{ + struct _uart_pl011_reg_map_t* p_uart = + (struct _uart_pl011_reg_map_t*)dev->cfg->base; + + _uart_pl011_set_cr_bit(p_uart, UART_PL011_UARTCR_LBE_MASK); + + return; +} + +void uart_pl011_clear_loopback(struct uart_pl011_dev_t* dev) +{ + struct _uart_pl011_reg_map_t* p_uart = + (struct _uart_pl011_reg_map_t*)dev->cfg->base; + + _uart_pl011_clear_cr_bit(p_uart, UART_PL011_UARTCR_LBE_MASK); + + return; +} + +void uart_pl011_enable_sirlp(struct uart_pl011_dev_t* dev) +{ + struct _uart_pl011_reg_map_t* p_uart = + (struct _uart_pl011_reg_map_t*)dev->cfg->base; + + _uart_pl011_set_cr_bit(p_uart, + UART_PL011_UARTCR_SIREN_MASK | UART_PL011_UARTCR_SIRLP_MASK); + + return; +} + +void uart_pl011_disable_sirlp(struct uart_pl011_dev_t* dev) +{ + struct _uart_pl011_reg_map_t* p_uart = + (struct _uart_pl011_reg_map_t*)dev->cfg->base; + + _uart_pl011_clear_cr_bit(p_uart, + UART_PL011_UARTCR_SIREN_MASK | UART_PL011_UARTCR_SIRLP_MASK); + + return; +} + +void uart_pl011_enable_sir(struct uart_pl011_dev_t* dev) +{ + struct _uart_pl011_reg_map_t* p_uart = + (struct _uart_pl011_reg_map_t*)dev->cfg->base; + + _uart_pl011_set_cr_bit(p_uart, UART_PL011_UARTCR_SIREN_MASK); + + return; +} + +void uart_pl011_disable_sir(struct uart_pl011_dev_t* dev) +{ + struct _uart_pl011_reg_map_t* p_uart = + (struct _uart_pl011_reg_map_t*)dev->cfg->base; + + _uart_pl011_clear_cr_bit(p_uart, UART_PL011_UARTCR_SIREN_MASK); + + return; +} + +void uart_pl011_enable(struct uart_pl011_dev_t* dev) +{ + struct _uart_pl011_reg_map_t* p_uart = + (struct _uart_pl011_reg_map_t*)dev->cfg->base; + + _uart_pl011_enable(p_uart); + + return; +} + +void uart_pl011_disable(struct uart_pl011_dev_t* dev) +{ + struct _uart_pl011_reg_map_t* p_uart = + (struct _uart_pl011_reg_map_t*)dev->cfg->base; + + _uart_pl011_disable(p_uart); + + return; +} + +bool uart_pl011_get_cts_status(struct uart_pl011_dev_t* dev) +{ + struct _uart_pl011_reg_map_t* p_uart = + (struct _uart_pl011_reg_map_t*)dev->cfg->base; + return (bool)(p_uart->uartfr & UART_PL011_UARTFR_CTS_MASK); + +} + +bool uart_pl011_get_dsr_status(struct uart_pl011_dev_t* dev) +{ + struct _uart_pl011_reg_map_t* p_uart = + (struct _uart_pl011_reg_map_t*)dev->cfg->base; + return (bool)(p_uart->uartfr & UART_PL011_UARTFR_DSR_MASK); + +} + +bool uart_pl011_get_dcd_status(struct uart_pl011_dev_t* dev) +{ + struct _uart_pl011_reg_map_t* p_uart = + (struct _uart_pl011_reg_map_t*)dev->cfg->base; + return (bool)(p_uart->uartfr & UART_PL011_UARTFR_DCD_MASK); + +} + +bool uart_pl011_get_ri_status(struct uart_pl011_dev_t* dev) +{ + struct _uart_pl011_reg_map_t* p_uart = + (struct _uart_pl011_reg_map_t*)dev->cfg->base; + return (bool)(p_uart->uartfr & UART_PL011_UARTFR_RI_MASK); + +} + +enum uart_pl011_error_t uart_pl011_set_sirlp_divisor( + struct uart_pl011_dev_t* dev, uint32_t value) +{ + struct _uart_pl011_reg_map_t* p_uart = + (struct _uart_pl011_reg_map_t*)dev->cfg->base; + + uint32_t irlp_baud16_clk; + + if(uart_pl011_get_state(dev) != UART_PL011_INITIALIZED) { + return UART_PL011_ERR_NOT_INIT; + } + + if(value == 0) { + return UART_PL011_ERR_INVALID_ARG; + } + + irlp_baud16_clk = dev->data->uart_clk/value; + + /* Chose the divisor so that 1.42MHz < FIrLPBaud16 < 2.12MHz, that + * results in a low-power pulse duration of 1.41–2.11μs (three times + * the period of IrLPBaud16). ARM DDI0183F Pg 3-9 */ + if(irlp_baud16_clk < FREQ_IRLPBAUD16_MIN || + irlp_baud16_clk > FREQ_IRLPBAUD16_MAX) { + return UART_PL011_ERR_INVALID_ARG; + } + + p_uart->uartilpr = value; + + return UART_PL011_ERR_NONE; +} |