driver: pl011: use new device model to map MMIO
Use the new device model introduced by device_mmio.h to map pl011 MMIO space. Signed-off-by: Luca Fancellu <luca.fancellu@arm.com>
This commit is contained in:
parent
0cc9ad4f50
commit
d62645200b
1 changed files with 51 additions and 73 deletions
|
@ -1,5 +1,6 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2018 Linaro Limited
|
* Copyright (c) 2018 Linaro Limited
|
||||||
|
* Copyright (c) 2022 Arm Limited (or its affiliates). All rights reserved.
|
||||||
*
|
*
|
||||||
* SPDX-License-Identifier: Apache-2.0
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
*/
|
*/
|
||||||
|
@ -12,6 +13,7 @@
|
||||||
#include <zephyr/init.h>
|
#include <zephyr/init.h>
|
||||||
#include <zephyr/device.h>
|
#include <zephyr/device.h>
|
||||||
#include <zephyr/drivers/uart.h>
|
#include <zephyr/drivers/uart.h>
|
||||||
|
#include <zephyr/sys/device_mmio.h>
|
||||||
|
|
||||||
#ifdef CONFIG_CPU_CORTEX_M
|
#ifdef CONFIG_CPU_CORTEX_M
|
||||||
#include <cmsis_compiler.h>
|
#include <cmsis_compiler.h>
|
||||||
|
@ -43,7 +45,7 @@ struct pl011_regs {
|
||||||
};
|
};
|
||||||
|
|
||||||
struct pl011_config {
|
struct pl011_config {
|
||||||
volatile struct pl011_regs *uart;
|
DEVICE_MMIO_ROM;
|
||||||
uint32_t sys_clk_freq;
|
uint32_t sys_clk_freq;
|
||||||
#ifdef CONFIG_UART_INTERRUPT_DRIVEN
|
#ifdef CONFIG_UART_INTERRUPT_DRIVEN
|
||||||
uart_irq_config_func_t irq_config_func;
|
uart_irq_config_func_t irq_config_func;
|
||||||
|
@ -52,6 +54,7 @@ struct pl011_config {
|
||||||
|
|
||||||
/* Device data structure */
|
/* Device data structure */
|
||||||
struct pl011_data {
|
struct pl011_data {
|
||||||
|
DEVICE_MMIO_RAM;
|
||||||
uint32_t baud_rate; /* Baud rate */
|
uint32_t baud_rate; /* Baud rate */
|
||||||
bool sbsa; /* SBSA mode */
|
bool sbsa; /* SBSA mode */
|
||||||
#ifdef CONFIG_UART_INTERRUPT_DRIVEN
|
#ifdef CONFIG_UART_INTERRUPT_DRIVEN
|
||||||
|
@ -153,39 +156,35 @@ struct pl011_data {
|
||||||
PL011_IMSC_RXIM | PL011_IMSC_TXIM | \
|
PL011_IMSC_RXIM | PL011_IMSC_TXIM | \
|
||||||
PL011_IMSC_RTIM)
|
PL011_IMSC_RTIM)
|
||||||
|
|
||||||
|
static inline
|
||||||
|
volatile struct pl011_regs *const get_uart(const struct device *dev)
|
||||||
|
{
|
||||||
|
return (volatile struct pl011_regs *const)DEVICE_MMIO_GET(dev);
|
||||||
|
}
|
||||||
|
|
||||||
static void pl011_enable(const struct device *dev)
|
static void pl011_enable(const struct device *dev)
|
||||||
{
|
{
|
||||||
const struct pl011_config *config = dev->config;
|
get_uart(dev)->cr |= PL011_CR_UARTEN;
|
||||||
|
|
||||||
config->uart->cr |= PL011_CR_UARTEN;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void pl011_disable(const struct device *dev)
|
static void pl011_disable(const struct device *dev)
|
||||||
{
|
{
|
||||||
const struct pl011_config *config = dev->config;
|
get_uart(dev)->cr &= ~PL011_CR_UARTEN;
|
||||||
|
|
||||||
config->uart->cr &= ~PL011_CR_UARTEN;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void pl011_enable_fifo(const struct device *dev)
|
static void pl011_enable_fifo(const struct device *dev)
|
||||||
{
|
{
|
||||||
const struct pl011_config *config = dev->config;
|
get_uart(dev)->lcr_h |= PL011_LCRH_FEN;
|
||||||
|
|
||||||
config->uart->lcr_h |= PL011_LCRH_FEN;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void pl011_disable_fifo(const struct device *dev)
|
static void pl011_disable_fifo(const struct device *dev)
|
||||||
{
|
{
|
||||||
const struct pl011_config *config = dev->config;
|
get_uart(dev)->lcr_h &= ~PL011_LCRH_FEN;
|
||||||
|
|
||||||
config->uart->lcr_h &= ~PL011_LCRH_FEN;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int pl011_set_baudrate(const struct device *dev,
|
static int pl011_set_baudrate(const struct device *dev,
|
||||||
uint32_t clk, uint32_t baudrate)
|
uint32_t clk, uint32_t baudrate)
|
||||||
{
|
{
|
||||||
const struct pl011_config *config = dev->config;
|
|
||||||
|
|
||||||
/* Avoiding float calculations, bauddiv is left shifted by 6 */
|
/* Avoiding float calculations, bauddiv is left shifted by 6 */
|
||||||
uint64_t bauddiv = (((uint64_t)clk) << PL011_FBRD_WIDTH)
|
uint64_t bauddiv = (((uint64_t)clk) << PL011_FBRD_WIDTH)
|
||||||
/ (baudrate * 16U);
|
/ (baudrate * 16U);
|
||||||
|
@ -199,8 +198,8 @@ static int pl011_set_baudrate(const struct device *dev,
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
config->uart->ibrd = bauddiv >> PL011_FBRD_WIDTH;
|
get_uart(dev)->ibrd = bauddiv >> PL011_FBRD_WIDTH;
|
||||||
config->uart->fbrd = bauddiv & ((1u << PL011_FBRD_WIDTH) - 1u);
|
get_uart(dev)->fbrd = bauddiv & ((1u << PL011_FBRD_WIDTH) - 1u);
|
||||||
|
|
||||||
__DMB();
|
__DMB();
|
||||||
|
|
||||||
|
@ -208,61 +207,55 @@ static int pl011_set_baudrate(const struct device *dev,
|
||||||
* lcr_h write must always be performed at the end
|
* lcr_h write must always be performed at the end
|
||||||
* ARM DDI 0183F, Pg 3-13
|
* ARM DDI 0183F, Pg 3-13
|
||||||
*/
|
*/
|
||||||
config->uart->lcr_h = config->uart->lcr_h;
|
get_uart(dev)->lcr_h = get_uart(dev)->lcr_h;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool pl011_is_readable(const struct device *dev)
|
static bool pl011_is_readable(const struct device *dev)
|
||||||
{
|
{
|
||||||
const struct pl011_config *config = dev->config;
|
|
||||||
struct pl011_data *data = dev->data;
|
struct pl011_data *data = dev->data;
|
||||||
|
|
||||||
if (!data->sbsa &&
|
if (!data->sbsa &&
|
||||||
(!(config->uart->cr & PL011_CR_UARTEN) ||
|
(!(get_uart(dev)->cr & PL011_CR_UARTEN) ||
|
||||||
!(config->uart->cr & PL011_CR_RXE)))
|
!(get_uart(dev)->cr & PL011_CR_RXE)))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
return (config->uart->fr & PL011_FR_RXFE) == 0U;
|
return (get_uart(dev)->fr & PL011_FR_RXFE) == 0U;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int pl011_poll_in(const struct device *dev, unsigned char *c)
|
static int pl011_poll_in(const struct device *dev, unsigned char *c)
|
||||||
{
|
{
|
||||||
const struct pl011_config *config = dev->config;
|
|
||||||
|
|
||||||
if (!pl011_is_readable(dev)) {
|
if (!pl011_is_readable(dev)) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* got a character */
|
/* got a character */
|
||||||
*c = (unsigned char)config->uart->dr;
|
*c = (unsigned char)get_uart(dev)->dr;
|
||||||
|
|
||||||
return config->uart->rsr & PL011_RSR_ERROR_MASK;
|
return get_uart(dev)->rsr & PL011_RSR_ERROR_MASK;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void pl011_poll_out(const struct device *dev,
|
static void pl011_poll_out(const struct device *dev,
|
||||||
unsigned char c)
|
unsigned char c)
|
||||||
{
|
{
|
||||||
const struct pl011_config *config = dev->config;
|
|
||||||
|
|
||||||
/* Wait for space in FIFO */
|
/* Wait for space in FIFO */
|
||||||
while (config->uart->fr & PL011_FR_TXFF) {
|
while (get_uart(dev)->fr & PL011_FR_TXFF) {
|
||||||
; /* Wait */
|
; /* Wait */
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Send a character */
|
/* Send a character */
|
||||||
config->uart->dr = (uint32_t)c;
|
get_uart(dev)->dr = (uint32_t)c;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef CONFIG_UART_INTERRUPT_DRIVEN
|
#ifdef CONFIG_UART_INTERRUPT_DRIVEN
|
||||||
static int pl011_fifo_fill(const struct device *dev,
|
static int pl011_fifo_fill(const struct device *dev,
|
||||||
const uint8_t *tx_data, int len)
|
const uint8_t *tx_data, int len)
|
||||||
{
|
{
|
||||||
const struct pl011_config *config = dev->config;
|
|
||||||
uint8_t num_tx = 0U;
|
uint8_t num_tx = 0U;
|
||||||
|
|
||||||
while (!(config->uart->fr & PL011_FR_TXFF) && (len - num_tx > 0)) {
|
while (!(get_uart(dev)->fr & PL011_FR_TXFF) && (len - num_tx > 0)) {
|
||||||
config->uart->dr = tx_data[num_tx++];
|
get_uart(dev)->dr = tx_data[num_tx++];
|
||||||
}
|
}
|
||||||
return num_tx;
|
return num_tx;
|
||||||
}
|
}
|
||||||
|
@ -270,11 +263,10 @@ static int pl011_fifo_fill(const struct device *dev,
|
||||||
static int pl011_fifo_read(const struct device *dev,
|
static int pl011_fifo_read(const struct device *dev,
|
||||||
uint8_t *rx_data, const int len)
|
uint8_t *rx_data, const int len)
|
||||||
{
|
{
|
||||||
const struct pl011_config *config = dev->config;
|
|
||||||
uint8_t num_rx = 0U;
|
uint8_t num_rx = 0U;
|
||||||
|
|
||||||
while ((len - num_rx > 0) && !(config->uart->fr & PL011_FR_RXFE)) {
|
while ((len - num_rx > 0) && !(get_uart(dev)->fr & PL011_FR_RXFE)) {
|
||||||
rx_data[num_rx++] = config->uart->dr;
|
rx_data[num_rx++] = get_uart(dev)->dr;
|
||||||
}
|
}
|
||||||
|
|
||||||
return num_rx;
|
return num_rx;
|
||||||
|
@ -282,77 +274,61 @@ static int pl011_fifo_read(const struct device *dev,
|
||||||
|
|
||||||
static void pl011_irq_tx_enable(const struct device *dev)
|
static void pl011_irq_tx_enable(const struct device *dev)
|
||||||
{
|
{
|
||||||
const struct pl011_config *config = dev->config;
|
get_uart(dev)->imsc |= PL011_IMSC_TXIM;
|
||||||
|
|
||||||
config->uart->imsc |= PL011_IMSC_TXIM;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void pl011_irq_tx_disable(const struct device *dev)
|
static void pl011_irq_tx_disable(const struct device *dev)
|
||||||
{
|
{
|
||||||
const struct pl011_config *config = dev->config;
|
get_uart(dev)->imsc &= ~PL011_IMSC_TXIM;
|
||||||
|
|
||||||
config->uart->imsc &= ~PL011_IMSC_TXIM;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int pl011_irq_tx_complete(const struct device *dev)
|
static int pl011_irq_tx_complete(const struct device *dev)
|
||||||
{
|
{
|
||||||
const struct pl011_config *config = dev->config;
|
|
||||||
|
|
||||||
/* check for TX FIFO empty */
|
/* check for TX FIFO empty */
|
||||||
return config->uart->fr & PL011_FR_TXFE;
|
return get_uart(dev)->fr & PL011_FR_TXFE;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int pl011_irq_tx_ready(const struct device *dev)
|
static int pl011_irq_tx_ready(const struct device *dev)
|
||||||
{
|
{
|
||||||
const struct pl011_config *config = dev->config;
|
|
||||||
struct pl011_data *data = dev->data;
|
struct pl011_data *data = dev->data;
|
||||||
|
|
||||||
if (!data->sbsa && !(config->uart->cr & PL011_CR_TXE))
|
if (!data->sbsa && !(get_uart(dev)->cr & PL011_CR_TXE))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
return ((config->uart->imsc & PL011_IMSC_TXIM) &&
|
return ((get_uart(dev)->imsc & PL011_IMSC_TXIM) &&
|
||||||
pl011_irq_tx_complete(dev));
|
pl011_irq_tx_complete(dev));
|
||||||
}
|
}
|
||||||
|
|
||||||
static void pl011_irq_rx_enable(const struct device *dev)
|
static void pl011_irq_rx_enable(const struct device *dev)
|
||||||
{
|
{
|
||||||
const struct pl011_config *config = dev->config;
|
get_uart(dev)->imsc |= PL011_IMSC_RXIM | PL011_IMSC_RTIM;
|
||||||
|
|
||||||
config->uart->imsc |= PL011_IMSC_RXIM | PL011_IMSC_RTIM;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void pl011_irq_rx_disable(const struct device *dev)
|
static void pl011_irq_rx_disable(const struct device *dev)
|
||||||
{
|
{
|
||||||
const struct pl011_config *config = dev->config;
|
get_uart(dev)->imsc &= ~(PL011_IMSC_RXIM | PL011_IMSC_RTIM);
|
||||||
|
|
||||||
config->uart->imsc &= ~(PL011_IMSC_RXIM | PL011_IMSC_RTIM);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int pl011_irq_rx_ready(const struct device *dev)
|
static int pl011_irq_rx_ready(const struct device *dev)
|
||||||
{
|
{
|
||||||
const struct pl011_config *config = dev->config;
|
|
||||||
struct pl011_data *data = dev->data;
|
struct pl011_data *data = dev->data;
|
||||||
|
|
||||||
if (!data->sbsa && !(config->uart->cr & PL011_CR_RXE))
|
if (!data->sbsa && !(get_uart(dev)->cr & PL011_CR_RXE))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
return ((config->uart->imsc & PL011_IMSC_RXIM) &&
|
return ((get_uart(dev)->imsc & PL011_IMSC_RXIM) &&
|
||||||
(!(config->uart->fr & PL011_FR_RXFE)));
|
(!(get_uart(dev)->fr & PL011_FR_RXFE)));
|
||||||
}
|
}
|
||||||
|
|
||||||
static void pl011_irq_err_enable(const struct device *dev)
|
static void pl011_irq_err_enable(const struct device *dev)
|
||||||
{
|
{
|
||||||
const struct pl011_config *config = dev->config;
|
|
||||||
|
|
||||||
/* enable framing, parity, break, and overrun */
|
/* enable framing, parity, break, and overrun */
|
||||||
config->uart->imsc |= PL011_IMSC_ERROR_MASK;
|
get_uart(dev)->imsc |= PL011_IMSC_ERROR_MASK;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void pl011_irq_err_disable(const struct device *dev)
|
static void pl011_irq_err_disable(const struct device *dev)
|
||||||
{
|
{
|
||||||
const struct pl011_config *config = dev->config;
|
get_uart(dev)->imsc &= ~PL011_IMSC_ERROR_MASK;
|
||||||
|
|
||||||
config->uart->imsc &= ~PL011_IMSC_ERROR_MASK;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int pl011_irq_is_pending(const struct device *dev)
|
static int pl011_irq_is_pending(const struct device *dev)
|
||||||
|
@ -404,6 +380,8 @@ static int pl011_init(const struct device *dev)
|
||||||
int ret;
|
int ret;
|
||||||
uint32_t lcrh;
|
uint32_t lcrh;
|
||||||
|
|
||||||
|
DEVICE_MMIO_MAP(dev, K_MEM_CACHE_NONE);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If working in SBSA mode, we assume that UART is already configured,
|
* If working in SBSA mode, we assume that UART is already configured,
|
||||||
* or does not require configuration at all (if UART is emulated by
|
* or does not require configuration at all (if UART is emulated by
|
||||||
|
@ -422,23 +400,23 @@ static int pl011_init(const struct device *dev)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Setting the default character format */
|
/* Setting the default character format */
|
||||||
lcrh = config->uart->lcr_h & ~(PL011_LCRH_FORMAT_MASK);
|
lcrh = get_uart(dev)->lcr_h & ~(PL011_LCRH_FORMAT_MASK);
|
||||||
lcrh &= ~(BIT(0) | BIT(7));
|
lcrh &= ~(BIT(0) | BIT(7));
|
||||||
lcrh |= PL011_LCRH_WLEN_SIZE(8) << PL011_LCRH_WLEN_SHIFT;
|
lcrh |= PL011_LCRH_WLEN_SIZE(8) << PL011_LCRH_WLEN_SHIFT;
|
||||||
config->uart->lcr_h = lcrh;
|
get_uart(dev)->lcr_h = lcrh;
|
||||||
|
|
||||||
/* Enabling the FIFOs */
|
/* Enabling the FIFOs */
|
||||||
pl011_enable_fifo(dev);
|
pl011_enable_fifo(dev);
|
||||||
}
|
}
|
||||||
/* initialize all IRQs as masked */
|
/* initialize all IRQs as masked */
|
||||||
config->uart->imsc = 0U;
|
get_uart(dev)->imsc = 0U;
|
||||||
config->uart->icr = PL011_IMSC_MASK_ALL;
|
get_uart(dev)->icr = PL011_IMSC_MASK_ALL;
|
||||||
|
|
||||||
if (!data->sbsa) {
|
if (!data->sbsa) {
|
||||||
config->uart->dmacr = 0U;
|
get_uart(dev)->dmacr = 0U;
|
||||||
__ISB();
|
__ISB();
|
||||||
config->uart->cr &= ~(BIT(14) | BIT(15) | BIT(1));
|
get_uart(dev)->cr &= ~(BIT(14) | BIT(15) | BIT(1));
|
||||||
config->uart->cr |= PL011_CR_RXE | PL011_CR_TXE;
|
get_uart(dev)->cr |= PL011_CR_RXE | PL011_CR_TXE;
|
||||||
__ISB();
|
__ISB();
|
||||||
}
|
}
|
||||||
#ifdef CONFIG_UART_INTERRUPT_DRIVEN
|
#ifdef CONFIG_UART_INTERRUPT_DRIVEN
|
||||||
|
@ -481,7 +459,7 @@ void pl011_isr(const struct device *dev)
|
||||||
}; \
|
}; \
|
||||||
\
|
\
|
||||||
static struct pl011_config pl011_cfg_port_##n = { \
|
static struct pl011_config pl011_cfg_port_##n = { \
|
||||||
.uart = (volatile struct pl011_regs *)DT_INST_REG_ADDR(n), \
|
DEVICE_MMIO_ROM_INIT(DT_DRV_INST(n)), \
|
||||||
.sys_clk_freq = DT_INST_PROP_BY_PHANDLE(n, clocks, clock_frequency), \
|
.sys_clk_freq = DT_INST_PROP_BY_PHANDLE(n, clocks, clock_frequency), \
|
||||||
.irq_config_func = pl011_irq_config_func_##n, \
|
.irq_config_func = pl011_irq_config_func_##n, \
|
||||||
};
|
};
|
||||||
|
@ -521,7 +499,7 @@ static void pl011_irq_config_func_sbsa(const struct device *dev);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static struct pl011_config pl011_cfg_sbsa = {
|
static struct pl011_config pl011_cfg_sbsa = {
|
||||||
.uart = (volatile struct pl011_regs *)DT_INST_REG_ADDR(0),
|
DEVICE_MMIO_ROM_INIT(DT_DRV_INST(0)),
|
||||||
#ifdef CONFIG_UART_INTERRUPT_DRIVEN
|
#ifdef CONFIG_UART_INTERRUPT_DRIVEN
|
||||||
.irq_config_func = pl011_irq_config_func_sbsa,
|
.irq_config_func = pl011_irq_config_func_sbsa,
|
||||||
#endif
|
#endif
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue