drivers: serial: uart_altera_jtag: enhancement
implement uart poll in and interrupt driven api. Signed-off-by: Goh Shun Jing <shun.jing.goh@intel.com>
This commit is contained in:
parent
712d682cf7
commit
5858cca8b8
3 changed files with 520 additions and 26 deletions
|
@ -1,14 +1,27 @@
|
||||||
|
# Copyright (c) 2017-2023 Intel Corporation
|
||||||
# SPDX-License-Identifier: Apache-2.0
|
# SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
config UART_ALTERA_JTAG
|
config UART_ALTERA_JTAG
|
||||||
bool "Nios II JTAG UART driver"
|
bool "Nios II/NiosV JTAG UART driver"
|
||||||
default y
|
default y
|
||||||
depends on DT_HAS_ALTR_JTAG_UART_ENABLED
|
depends on DT_HAS_ALTR_JTAG_UART_ENABLED
|
||||||
select SERIAL_HAS_DRIVER
|
select SERIAL_HAS_DRIVER
|
||||||
help
|
help
|
||||||
Enable the Altera JTAG UART driver, built in to many Nios II CPU
|
Enable the Altera JTAG UART driver, built in to many Nios II/NiosV CPU
|
||||||
designs.
|
designs.
|
||||||
|
|
||||||
config UART_ALTERA_JTAG_HAL
|
config UART_ALTERA_JTAG_HAL
|
||||||
bool "JTAG UART driver using Altera HAL API"
|
bool "JTAG UART driver using Altera HAL API"
|
||||||
|
depends on UART_ALTERA_JTAG && NIOS2
|
||||||
|
help
|
||||||
|
This is not available for NiosV CPU, as only the HAL for Nios II CPU is ported.
|
||||||
|
Enabling this will disable poll_in and interrupt driven api.
|
||||||
|
|
||||||
|
config UART_ALTERA_JTAG_SUPPORT_INTERRUPT
|
||||||
|
bool
|
||||||
depends on UART_ALTERA_JTAG
|
depends on UART_ALTERA_JTAG
|
||||||
|
default y if !UART_ALTERA_JTAG_HAL
|
||||||
|
select SERIAL_SUPPORT_INTERRUPT
|
||||||
|
help
|
||||||
|
This is a helper config. Altera JTAG UART driver will support interrupt,
|
||||||
|
if UART_ALTERA_JTAG_HAL is disabled.
|
||||||
|
|
|
@ -1,23 +1,37 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2017 Intel Corporation
|
* Copyright (c) 2017-2023 Intel Corporation
|
||||||
*
|
*
|
||||||
* SPDX-License-Identifier: Apache-2.0
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief UART driver for Intel FPGA UART Core IP
|
||||||
|
* Reference : Embedded Peripherals IP User Guide : 12. JTAG UART Core
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
#include <zephyr/kernel.h>
|
#include <zephyr/kernel.h>
|
||||||
#include <zephyr/arch/cpu.h>
|
#include <zephyr/arch/cpu.h>
|
||||||
#include <zephyr/drivers/uart.h>
|
#include <zephyr/drivers/uart.h>
|
||||||
#include <zephyr/sys/sys_io.h>
|
#include <zephyr/sys/sys_io.h>
|
||||||
|
|
||||||
|
#include <zephyr/sys/__assert.h>
|
||||||
|
|
||||||
#define DT_DRV_COMPAT altr_jtag_uart
|
#define DT_DRV_COMPAT altr_jtag_uart
|
||||||
|
|
||||||
#define UART_ALTERA_JTAG_DATA_OFFSET 0x00 /* DATA : Register offset */
|
#define UART_ALTERA_JTAG_DATA_OFFSET 0x00 /* DATA : Register offset */
|
||||||
#define UART_ALTERA_JTAG_CTRL_OFFSET 0x04 /* CTRL : Register offset */
|
#define UART_ALTERA_JTAG_CTRL_OFFSET 0x04 /* CTRL : Register offset */
|
||||||
#define UART_IE_TX (1 << 0) /* CTRL : TX Interrupt Enable */
|
#define UART_IE_TX (1 << 1) /* CTRL : TX Interrupt Enable */
|
||||||
#define UART_IE_RX (1 << 1) /* CTRL : RX Interrupt Enable */
|
#define UART_IE_RX (1 << 0) /* CTRL : RX Interrupt Enable */
|
||||||
#define UART_DATA_MASK 0xFF /* DATA : Data Mask */
|
#define UART_DATA_MASK 0xFF /* DATA : Data Mask */
|
||||||
#define UART_WFIFO_MASK 0xFFFF0000 /* CTRL : Transmit FIFO Mask */
|
#define UART_WFIFO_MASK 0xFFFF0000 /* CTRL : Transmit FIFO Mask */
|
||||||
|
#define UART_WFIFO_OFST (16)
|
||||||
|
|
||||||
|
#define ALTERA_AVALON_JTAG_UART_DATA_DATA_OFST (0)
|
||||||
|
#define ALTERA_AVALON_JTAG_UART_DATA_RVALID_MSK (0x00008000)
|
||||||
|
|
||||||
|
#define ALTERA_AVALON_JTAG_UART_CONTROL_RI_MSK (0x00000100)
|
||||||
|
#define ALTERA_AVALON_JTAG_UART_CONTROL_WI_MSK (0x00000200)
|
||||||
|
|
||||||
#ifdef CONFIG_UART_ALTERA_JTAG_HAL
|
#ifdef CONFIG_UART_ALTERA_JTAG_HAL
|
||||||
#include "altera_avalon_jtag_uart.h"
|
#include "altera_avalon_jtag_uart.h"
|
||||||
|
@ -32,14 +46,75 @@ extern int altera_avalon_jtag_uart_write(altera_avalon_jtag_uart_state *sp,
|
||||||
/* device data */
|
/* device data */
|
||||||
struct uart_altera_jtag_device_data {
|
struct uart_altera_jtag_device_data {
|
||||||
struct k_spinlock lock;
|
struct k_spinlock lock;
|
||||||
|
#ifdef CONFIG_UART_INTERRUPT_DRIVEN
|
||||||
|
uart_irq_callback_user_data_t cb; /* Callback function pointer */
|
||||||
|
void *cb_data; /* Callback function arg */
|
||||||
|
#endif /* CONFIG_UART_INTERRUPT_DRIVEN */
|
||||||
};
|
};
|
||||||
|
|
||||||
/* device config */
|
/* device config */
|
||||||
struct uart_altera_jtag_device_config {
|
struct uart_altera_jtag_device_config {
|
||||||
mm_reg_t base;
|
mm_reg_t base;
|
||||||
|
#ifdef CONFIG_UART_INTERRUPT_DRIVEN
|
||||||
|
uart_irq_config_func_t irq_config_func;
|
||||||
|
unsigned int irq_num;
|
||||||
|
uint16_t write_fifo_depth;
|
||||||
|
#endif /* CONFIG_UART_INTERRUPT_DRIVEN */
|
||||||
};
|
};
|
||||||
#endif /* CONFIG_UART_ALTERA_JTAG_HAL */
|
#endif /* CONFIG_UART_ALTERA_JTAG_HAL */
|
||||||
|
|
||||||
|
#ifndef CONFIG_UART_ALTERA_JTAG_HAL
|
||||||
|
/**
|
||||||
|
* @brief Poll the device for input.
|
||||||
|
*
|
||||||
|
* @param dev UART device instance
|
||||||
|
* @param c Pointer to character
|
||||||
|
*
|
||||||
|
* @return 0 if a character arrived, -1 otherwise.
|
||||||
|
* -EINVAL if c is null pointer.
|
||||||
|
*/
|
||||||
|
static int uart_altera_jtag_poll_in(const struct device *dev,
|
||||||
|
unsigned char *c)
|
||||||
|
{
|
||||||
|
int ret = -1;
|
||||||
|
const struct uart_altera_jtag_device_config *config = dev->config;
|
||||||
|
struct uart_altera_jtag_device_data *data = dev->data;
|
||||||
|
unsigned int input_data;
|
||||||
|
|
||||||
|
/* generate fatal error if CONFIG_ASSERT is enabled. */
|
||||||
|
__ASSERT(c != NULL, "c is null pointer!");
|
||||||
|
|
||||||
|
/* Stop, if c is null pointer */
|
||||||
|
if (c == NULL) {
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
k_spinlock_key_t key = k_spin_lock(&data->lock);
|
||||||
|
|
||||||
|
input_data = sys_read32(config->base + UART_ALTERA_JTAG_DATA_OFFSET);
|
||||||
|
|
||||||
|
/* check if data is valid. */
|
||||||
|
if (input_data & ALTERA_AVALON_JTAG_UART_DATA_RVALID_MSK) {
|
||||||
|
*c = (input_data & UART_DATA_MASK) >> ALTERA_AVALON_JTAG_UART_DATA_DATA_OFST;
|
||||||
|
ret = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
k_spin_unlock(&data->lock, key);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
#endif /* CONFIG_UART_ALTERA_JTAG_HAL */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Output a character in polled mode.
|
||||||
|
*
|
||||||
|
* This routine checks if the transmitter is full.
|
||||||
|
* When the transmitter is not full, it writes a character to the data register.
|
||||||
|
* It waits and blocks the calling thread, otherwise. This function is a blocking call.
|
||||||
|
*
|
||||||
|
* @param dev UART device instance
|
||||||
|
* @param c Character to send
|
||||||
|
*/
|
||||||
static void uart_altera_jtag_poll_out(const struct device *dev,
|
static void uart_altera_jtag_poll_out(const struct device *dev,
|
||||||
unsigned char c)
|
unsigned char c)
|
||||||
{
|
{
|
||||||
|
@ -58,16 +133,21 @@ static void uart_altera_jtag_poll_out(const struct device *dev,
|
||||||
while (!(sys_read32(config->base + UART_ALTERA_JTAG_CTRL_OFFSET) & UART_WFIFO_MASK)) {
|
while (!(sys_read32(config->base + UART_ALTERA_JTAG_CTRL_OFFSET) & UART_WFIFO_MASK)) {
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t data_val = sys_read32(config->base + UART_ALTERA_JTAG_DATA_OFFSET);
|
sys_write8(c, config->base + UART_ALTERA_JTAG_DATA_OFFSET);
|
||||||
|
|
||||||
data_val &= ~UART_DATA_MASK;
|
|
||||||
data_val |= c;
|
|
||||||
sys_write32(data_val, config->base + UART_ALTERA_JTAG_DATA_OFFSET);
|
|
||||||
|
|
||||||
k_spin_unlock(&data->lock, key);
|
k_spin_unlock(&data->lock, key);
|
||||||
#endif /* CONFIG_UART_ALTERA_JTAG_HAL */
|
#endif /* CONFIG_UART_ALTERA_JTAG_HAL */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Initialise an instance of the driver
|
||||||
|
*
|
||||||
|
* This function initialise the interrupt configuration for the driver.
|
||||||
|
*
|
||||||
|
* @param dev UART device instance
|
||||||
|
*
|
||||||
|
* @return 0 to indicate success.
|
||||||
|
*/
|
||||||
static int uart_altera_jtag_init(const struct device *dev)
|
static int uart_altera_jtag_init(const struct device *dev)
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
|
@ -80,35 +160,429 @@ static int uart_altera_jtag_init(const struct device *dev)
|
||||||
const struct uart_altera_jtag_device_config *config = dev->config;
|
const struct uart_altera_jtag_device_config *config = dev->config;
|
||||||
uint32_t ctrl_val = sys_read32(config->base + UART_ALTERA_JTAG_CTRL_OFFSET);
|
uint32_t ctrl_val = sys_read32(config->base + UART_ALTERA_JTAG_CTRL_OFFSET);
|
||||||
|
|
||||||
|
#ifdef CONFIG_UART_INTERRUPT_DRIVEN
|
||||||
|
/*
|
||||||
|
* Enable hardware interrupt.
|
||||||
|
* The corresponding csr from IP still needs to be set,
|
||||||
|
* so that the IP generates interrupt signal.
|
||||||
|
*/
|
||||||
|
config->irq_config_func(dev);
|
||||||
|
#endif
|
||||||
|
/* Disable the tx and rx interrupt signals from JTAG core IP. */
|
||||||
ctrl_val &= ~(UART_IE_TX | UART_IE_RX);
|
ctrl_val &= ~(UART_IE_TX | UART_IE_RX);
|
||||||
sys_write32(ctrl_val, config->base + UART_ALTERA_JTAG_CTRL_OFFSET);
|
sys_write32(ctrl_val, config->base + UART_ALTERA_JTAG_CTRL_OFFSET);
|
||||||
#endif /* CONFIG_UART_ALTERA_JTAG_HAL */
|
#endif /* CONFIG_UART_ALTERA_JTAG_HAL */
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Functions for Interrupt driven API
|
||||||
|
*/
|
||||||
|
#if defined(CONFIG_UART_INTERRUPT_DRIVEN) && !defined(CONFIG_UART_ALTERA_JTAG_HAL)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Fill FIFO with data
|
||||||
|
* This function is expected to be called from UART interrupt handler (ISR),
|
||||||
|
* if uart_irq_tx_ready() returns true.
|
||||||
|
*
|
||||||
|
* @param dev UART device instance
|
||||||
|
* @param tx_data Data to transmit
|
||||||
|
* @param size Number of bytes to send
|
||||||
|
*
|
||||||
|
* @return Number of bytes sent
|
||||||
|
*/
|
||||||
|
static int uart_altera_jtag_fifo_fill(const struct device *dev,
|
||||||
|
const uint8_t *tx_data,
|
||||||
|
int size)
|
||||||
|
{
|
||||||
|
const struct uart_altera_jtag_device_config *config = dev->config;
|
||||||
|
struct uart_altera_jtag_device_data *data = dev->data;
|
||||||
|
uint32_t ctrl_val;
|
||||||
|
uint32_t space = 0;
|
||||||
|
|
||||||
|
int i;
|
||||||
|
|
||||||
|
/* generate fatal error if CONFIG_ASSERT is enabled. */
|
||||||
|
__ASSERT(tx_data != NULL, "tx buffer is null pointer!");
|
||||||
|
|
||||||
|
/* Stop, if buffer is null pointer */
|
||||||
|
if (tx_data == NULL) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
k_spinlock_key_t key = k_spin_lock(&data->lock);
|
||||||
|
|
||||||
|
ctrl_val = sys_read32(config->base + UART_ALTERA_JTAG_CTRL_OFFSET);
|
||||||
|
space = (ctrl_val & UART_WFIFO_MASK) >> UART_WFIFO_OFST;
|
||||||
|
|
||||||
|
/* guard for tx data overflow:
|
||||||
|
* make sure that driver is not sending more than current available space.
|
||||||
|
*/
|
||||||
|
for (i = 0; (i < size) && (i < space); i++) {
|
||||||
|
sys_write8(tx_data[i], config->base + UART_ALTERA_JTAG_DATA_OFFSET);
|
||||||
|
}
|
||||||
|
|
||||||
|
k_spin_unlock(&data->lock, key);
|
||||||
|
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Read data from FIFO
|
||||||
|
* This function is expected to be called from UART interrupt handler (ISR),
|
||||||
|
* if uart_irq_rx_ready() returns true.
|
||||||
|
*
|
||||||
|
* @param dev UART device instance
|
||||||
|
* @param rx_data Data container
|
||||||
|
* @param size Container size
|
||||||
|
*
|
||||||
|
* @return Number of bytes read
|
||||||
|
*/
|
||||||
|
static int uart_altera_jtag_fifo_read(const struct device *dev, uint8_t *rx_data,
|
||||||
|
const int size)
|
||||||
|
{
|
||||||
|
const struct uart_altera_jtag_device_config *config = dev->config;
|
||||||
|
struct uart_altera_jtag_device_data *data = dev->data;
|
||||||
|
int i;
|
||||||
|
unsigned int input_data;
|
||||||
|
|
||||||
|
/* generate fatal error if CONFIG_ASSERT is enabled. */
|
||||||
|
__ASSERT(rx_data != NULL, "Rx buffer is null pointer!");
|
||||||
|
|
||||||
|
/* Stop, if buffer is null pointer */
|
||||||
|
if (rx_data == NULL) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
k_spinlock_key_t key = k_spin_lock(&data->lock);
|
||||||
|
|
||||||
|
for (i = 0; i < size; i++) {
|
||||||
|
input_data = sys_read32(config->base + UART_ALTERA_JTAG_DATA_OFFSET);
|
||||||
|
|
||||||
|
if (input_data & ALTERA_AVALON_JTAG_UART_DATA_RVALID_MSK) {
|
||||||
|
rx_data[i] = (input_data & UART_DATA_MASK) >>
|
||||||
|
ALTERA_AVALON_JTAG_UART_DATA_DATA_OFST;
|
||||||
|
} else {
|
||||||
|
/* break upon invalid data or no more data */
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
k_spin_unlock(&data->lock, key);
|
||||||
|
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Enable TX interrupt in IER
|
||||||
|
*
|
||||||
|
* @param dev UART device instance
|
||||||
|
*/
|
||||||
|
static void uart_altera_jtag_irq_tx_enable(const struct device *dev)
|
||||||
|
{
|
||||||
|
struct uart_altera_jtag_device_data *data = dev->data;
|
||||||
|
const struct uart_altera_jtag_device_config *config = dev->config;
|
||||||
|
uint32_t ctrl_val = sys_read32(config->base + UART_ALTERA_JTAG_CTRL_OFFSET);
|
||||||
|
|
||||||
|
k_spinlock_key_t key = k_spin_lock(&data->lock);
|
||||||
|
|
||||||
|
ctrl_val |= UART_IE_TX;
|
||||||
|
sys_write32(ctrl_val, config->base + UART_ALTERA_JTAG_CTRL_OFFSET);
|
||||||
|
|
||||||
|
k_spin_unlock(&data->lock, key);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Disable TX interrupt in IER
|
||||||
|
*
|
||||||
|
* @param dev UART device instance
|
||||||
|
*/
|
||||||
|
static void uart_altera_jtag_irq_tx_disable(const struct device *dev)
|
||||||
|
{
|
||||||
|
struct uart_altera_jtag_device_data *data = dev->data;
|
||||||
|
const struct uart_altera_jtag_device_config *config = dev->config;
|
||||||
|
uint32_t ctrl_val = sys_read32(config->base + UART_ALTERA_JTAG_CTRL_OFFSET);
|
||||||
|
|
||||||
|
k_spinlock_key_t key = k_spin_lock(&data->lock);
|
||||||
|
|
||||||
|
ctrl_val &= ~UART_IE_TX;
|
||||||
|
sys_write32(ctrl_val, config->base + UART_ALTERA_JTAG_CTRL_OFFSET);
|
||||||
|
|
||||||
|
k_spin_unlock(&data->lock, key);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Check if UART TX buffer can accept a new char.
|
||||||
|
*
|
||||||
|
* @param dev UART device instance
|
||||||
|
*
|
||||||
|
* @return 1 if TX interrupt is enabled and at least one char can be written to UART.
|
||||||
|
* 0 If device is not ready to write a new byte.
|
||||||
|
*/
|
||||||
|
static int uart_altera_jtag_irq_tx_ready(const struct device *dev)
|
||||||
|
{
|
||||||
|
struct uart_altera_jtag_device_data *data = dev->data;
|
||||||
|
const struct uart_altera_jtag_device_config *config = dev->config;
|
||||||
|
uint32_t ctrl_val = sys_read32(config->base + UART_ALTERA_JTAG_CTRL_OFFSET);
|
||||||
|
int ret = 0;
|
||||||
|
uint32_t space = 0;
|
||||||
|
|
||||||
|
k_spinlock_key_t key = k_spin_lock(&data->lock);
|
||||||
|
|
||||||
|
/* if TX interrupt is enabled */
|
||||||
|
if (ctrl_val & ALTERA_AVALON_JTAG_UART_CONTROL_WI_MSK) {
|
||||||
|
/* check for space in tx fifo */
|
||||||
|
space = (ctrl_val & UART_WFIFO_MASK) >> UART_WFIFO_OFST;
|
||||||
|
if (space) {
|
||||||
|
ret = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
k_spin_unlock(&data->lock, key);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Check if nothing remains to be transmitted
|
||||||
|
*
|
||||||
|
* @param dev UART device instance
|
||||||
|
*
|
||||||
|
* @return 1 if nothing remains to be transmitted, 0 otherwise
|
||||||
|
*/
|
||||||
|
static int uart_altera_jtag_irq_tx_complete(const struct device *dev)
|
||||||
|
{
|
||||||
|
struct uart_altera_jtag_device_data *data = dev->data;
|
||||||
|
const struct uart_altera_jtag_device_config *config = dev->config;
|
||||||
|
uint32_t ctrl_val = sys_read32(config->base + UART_ALTERA_JTAG_CTRL_OFFSET);
|
||||||
|
int ret = 0;
|
||||||
|
uint32_t space = 0;
|
||||||
|
|
||||||
|
k_spinlock_key_t key = k_spin_lock(&data->lock);
|
||||||
|
|
||||||
|
/* note: This is checked indirectly via the space in tx fifo. */
|
||||||
|
space = (ctrl_val & UART_WFIFO_MASK) >> UART_WFIFO_OFST;
|
||||||
|
if (space == config->write_fifo_depth) {
|
||||||
|
ret = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
k_spin_unlock(&data->lock, key);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Enable RX interrupt in IER
|
||||||
|
*
|
||||||
|
* @param dev UART device instance
|
||||||
|
*/
|
||||||
|
static void uart_altera_jtag_irq_rx_enable(const struct device *dev)
|
||||||
|
{
|
||||||
|
struct uart_altera_jtag_device_data *data = dev->data;
|
||||||
|
const struct uart_altera_jtag_device_config *config = dev->config;
|
||||||
|
uint32_t ctrl_val = sys_read32(config->base + UART_ALTERA_JTAG_CTRL_OFFSET);
|
||||||
|
|
||||||
|
k_spinlock_key_t key = k_spin_lock(&data->lock);
|
||||||
|
|
||||||
|
ctrl_val |= UART_IE_RX;
|
||||||
|
sys_write32(ctrl_val, config->base + UART_ALTERA_JTAG_CTRL_OFFSET);
|
||||||
|
|
||||||
|
k_spin_unlock(&data->lock, key);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Disable RX interrupt in IER
|
||||||
|
*
|
||||||
|
* @param dev UART device instance
|
||||||
|
*/
|
||||||
|
static void uart_altera_jtag_irq_rx_disable(const struct device *dev)
|
||||||
|
{
|
||||||
|
struct uart_altera_jtag_device_data *data = dev->data;
|
||||||
|
const struct uart_altera_jtag_device_config *config = dev->config;
|
||||||
|
uint32_t ctrl_val = sys_read32(config->base + UART_ALTERA_JTAG_CTRL_OFFSET);
|
||||||
|
|
||||||
|
k_spinlock_key_t key = k_spin_lock(&data->lock);
|
||||||
|
|
||||||
|
ctrl_val &= ~UART_IE_RX;
|
||||||
|
sys_write32(ctrl_val, config->base + UART_ALTERA_JTAG_CTRL_OFFSET);
|
||||||
|
|
||||||
|
k_spin_unlock(&data->lock, key);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Check if Rx IRQ has been raised
|
||||||
|
*
|
||||||
|
* @param dev UART device instance
|
||||||
|
*
|
||||||
|
* @return 1 if an IRQ is ready, 0 otherwise
|
||||||
|
*/
|
||||||
|
static int uart_altera_jtag_irq_rx_ready(const struct device *dev)
|
||||||
|
{
|
||||||
|
struct uart_altera_jtag_device_data *data = dev->data;
|
||||||
|
const struct uart_altera_jtag_device_config *config = dev->config;
|
||||||
|
uint32_t ctrl_val = sys_read32(config->base + UART_ALTERA_JTAG_CTRL_OFFSET);
|
||||||
|
int ret = 0;
|
||||||
|
|
||||||
|
k_spinlock_key_t key = k_spin_lock(&data->lock);
|
||||||
|
|
||||||
|
if (ctrl_val & ALTERA_AVALON_JTAG_UART_CONTROL_RI_MSK) {
|
||||||
|
ret = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
k_spin_unlock(&data->lock, key);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Update cached contents of IIR
|
||||||
|
*
|
||||||
|
* @param dev UART device instance
|
||||||
|
*
|
||||||
|
* @return Always 1
|
||||||
|
*/
|
||||||
|
static int uart_altera_jtag_irq_update(const struct device *dev)
|
||||||
|
{
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Check if any IRQ is pending
|
||||||
|
*
|
||||||
|
* @param dev UART device instance
|
||||||
|
*
|
||||||
|
* @return 1 if an IRQ is pending, 0 otherwise
|
||||||
|
*/
|
||||||
|
static int uart_altera_jtag_irq_is_pending(const struct device *dev)
|
||||||
|
{
|
||||||
|
struct uart_altera_jtag_device_data *data = dev->data;
|
||||||
|
k_spinlock_key_t key = k_spin_lock(&data->lock);
|
||||||
|
const struct uart_altera_jtag_device_config *config = dev->config;
|
||||||
|
uint32_t ctrl_val = sys_read32(config->base + UART_ALTERA_JTAG_CTRL_OFFSET);
|
||||||
|
int ret = 0;
|
||||||
|
|
||||||
|
if (ctrl_val &
|
||||||
|
(ALTERA_AVALON_JTAG_UART_CONTROL_RI_MSK|ALTERA_AVALON_JTAG_UART_CONTROL_WI_MSK)) {
|
||||||
|
ret = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
k_spin_unlock(&data->lock, key);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Set the callback function pointer for IRQ.
|
||||||
|
*
|
||||||
|
* @param dev UART device instance
|
||||||
|
* @param cb Callback function pointer.
|
||||||
|
* @param cb_data Data to pass to callback function.
|
||||||
|
*/
|
||||||
|
static void uart_altera_jtag_irq_callback_set(const struct device *dev,
|
||||||
|
uart_irq_callback_user_data_t cb,
|
||||||
|
void *cb_data)
|
||||||
|
{
|
||||||
|
struct uart_altera_jtag_device_data *data = dev->data;
|
||||||
|
|
||||||
|
/* generate fatal error if CONFIG_ASSERT is enabled. */
|
||||||
|
__ASSERT(cb != NULL, "uart_irq_callback_user_data_t cb is null pointer!");
|
||||||
|
|
||||||
|
k_spinlock_key_t key = k_spin_lock(&data->lock);
|
||||||
|
|
||||||
|
data->cb = cb;
|
||||||
|
data->cb_data = cb_data;
|
||||||
|
|
||||||
|
k_spin_unlock(&data->lock, key);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Interrupt service routine.
|
||||||
|
*
|
||||||
|
* This simply calls the callback function, if one exists.
|
||||||
|
*
|
||||||
|
* @param dev Pointer to UART device struct
|
||||||
|
*/
|
||||||
|
static void uart_altera_jtag_isr(const struct device *dev)
|
||||||
|
{
|
||||||
|
struct uart_altera_jtag_device_data *data = dev->data;
|
||||||
|
uart_irq_callback_user_data_t callback = data->cb;
|
||||||
|
|
||||||
|
if (callback) {
|
||||||
|
callback(dev, data->cb_data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* CONFIG_UART_INTERRUPT_DRIVEN && !CONFIG_UART_ALTERA_JTAG_HAL */
|
||||||
|
|
||||||
static const struct uart_driver_api uart_altera_jtag_driver_api = {
|
static const struct uart_driver_api uart_altera_jtag_driver_api = {
|
||||||
.poll_in = NULL,
|
#ifndef CONFIG_UART_ALTERA_JTAG_HAL
|
||||||
.poll_out = &uart_altera_jtag_poll_out,
|
.poll_in = uart_altera_jtag_poll_in,
|
||||||
|
#endif /* CONFIG_UART_ALTERA_JTAG_HAL */
|
||||||
|
.poll_out = uart_altera_jtag_poll_out,
|
||||||
.err_check = NULL,
|
.err_check = NULL,
|
||||||
|
#if defined(CONFIG_UART_INTERRUPT_DRIVEN) && !defined(CONFIG_UART_ALTERA_JTAG_HAL)
|
||||||
|
.fifo_fill = uart_altera_jtag_fifo_fill,
|
||||||
|
.fifo_read = uart_altera_jtag_fifo_read,
|
||||||
|
.irq_tx_enable = uart_altera_jtag_irq_tx_enable,
|
||||||
|
.irq_tx_disable = uart_altera_jtag_irq_tx_disable,
|
||||||
|
.irq_tx_ready = uart_altera_jtag_irq_tx_ready,
|
||||||
|
.irq_tx_complete = uart_altera_jtag_irq_tx_complete,
|
||||||
|
.irq_rx_enable = uart_altera_jtag_irq_rx_enable,
|
||||||
|
.irq_rx_disable = uart_altera_jtag_irq_rx_disable,
|
||||||
|
.irq_rx_ready = uart_altera_jtag_irq_rx_ready,
|
||||||
|
.irq_is_pending = uart_altera_jtag_irq_is_pending,
|
||||||
|
.irq_update = uart_altera_jtag_irq_update,
|
||||||
|
.irq_callback_set = uart_altera_jtag_irq_callback_set,
|
||||||
|
#endif /* CONFIG_UART_INTERRUPT_DRIVEN && !CONFIG_UART_ALTERA_JTAG_HAL */
|
||||||
};
|
};
|
||||||
|
|
||||||
#ifdef CONFIG_UART_ALTERA_JTAG_HAL
|
#ifdef CONFIG_UART_ALTERA_JTAG_HAL
|
||||||
DEVICE_DT_INST_DEFINE(0, uart_altera_jtag_init, NULL, NULL, NULL, PRE_KERNEL_1,
|
#define UART_ALTERA_JTAG_DEVICE_INIT(n) \
|
||||||
CONFIG_SERIAL_INIT_PRIORITY,
|
DEVICE_DT_INST_DEFINE(n, uart_altera_jtag_init, NULL, NULL, NULL, PRE_KERNEL_1, \
|
||||||
|
CONFIG_SERIAL_INIT_PRIORITY, \
|
||||||
&uart_altera_jtag_driver_api);
|
&uart_altera_jtag_driver_api);
|
||||||
#else
|
#else
|
||||||
static struct uart_altera_jtag_device_data uart_altera_jtag_dev_data_0 = {
|
|
||||||
};
|
|
||||||
|
|
||||||
static const struct uart_altera_jtag_device_config uart_altera_jtag_dev_cfg_0 = {
|
#ifdef CONFIG_UART_INTERRUPT_DRIVEN
|
||||||
.base = DT_INST_REG_ADDR(0),
|
#define UART_ALTERA_JTAG_CONFIG_FUNC(n) \
|
||||||
};
|
static void uart_altera_jtag_irq_config_func_##n(const struct device *dev) \
|
||||||
DEVICE_DT_INST_DEFINE(0,
|
{ \
|
||||||
uart_altera_jtag_init,
|
IRQ_CONNECT(DT_INST_IRQN(n), \
|
||||||
NULL,
|
DT_INST_IRQ(n, priority), \
|
||||||
&uart_altera_jtag_dev_data_0,
|
uart_altera_jtag_isr, \
|
||||||
&uart_altera_jtag_dev_cfg_0,
|
DEVICE_DT_INST_GET(n), 0); \
|
||||||
PRE_KERNEL_1,
|
\
|
||||||
CONFIG_SERIAL_INIT_PRIORITY,
|
irq_enable(DT_INST_IRQN(n)); \
|
||||||
|
}
|
||||||
|
|
||||||
|
#define UART_ALTERA_JTAG_CONFIG_INIT(n) \
|
||||||
|
.irq_config_func = uart_altera_jtag_irq_config_func_##n, \
|
||||||
|
.irq_num = DT_INST_IRQN(n), \
|
||||||
|
.write_fifo_depth = DT_INST_PROP_OR(n, write_fifo_depth, 0),\
|
||||||
|
|
||||||
|
#else
|
||||||
|
#define UART_ALTERA_JTAG_CONFIG_FUNC(n)
|
||||||
|
#define UART_ALTERA_JTAG_CONFIG_INIT(n)
|
||||||
|
#define UART_ALTERA_JTAG_DATA_INIT(n)
|
||||||
|
#endif /* CONFIG_UART_INTERRUPT_DRIVEN */
|
||||||
|
|
||||||
|
#define UART_ALTERA_JTAG_DEVICE_INIT(n) \
|
||||||
|
UART_ALTERA_JTAG_CONFIG_FUNC(n) \
|
||||||
|
static struct uart_altera_jtag_device_data uart_altera_jtag_device_data_##n = { \
|
||||||
|
}; \
|
||||||
|
\
|
||||||
|
static const struct uart_altera_jtag_device_config uart_altera_jtag_dev_cfg_##n = { \
|
||||||
|
.base = DT_INST_REG_ADDR(n), \
|
||||||
|
UART_ALTERA_JTAG_CONFIG_INIT(n) \
|
||||||
|
}; \
|
||||||
|
DEVICE_DT_INST_DEFINE(n, \
|
||||||
|
uart_altera_jtag_init, \
|
||||||
|
NULL, \
|
||||||
|
&uart_altera_jtag_device_data_##n, \
|
||||||
|
&uart_altera_jtag_dev_cfg_##n, \
|
||||||
|
PRE_KERNEL_1, \
|
||||||
|
CONFIG_SERIAL_INIT_PRIORITY, \
|
||||||
&uart_altera_jtag_driver_api);
|
&uart_altera_jtag_driver_api);
|
||||||
#endif /* CONFIG_UART_ALTERA_JTAG_HAL */
|
#endif /* CONFIG_UART_ALTERA_JTAG_HAL */
|
||||||
|
|
||||||
|
DT_INST_FOREACH_STATUS_OKAY(UART_ALTERA_JTAG_DEVICE_INIT)
|
||||||
|
|
|
@ -7,3 +7,10 @@ include: uart-controller.yaml
|
||||||
properties:
|
properties:
|
||||||
reg:
|
reg:
|
||||||
required: true
|
required: true
|
||||||
|
|
||||||
|
write-fifo-depth:
|
||||||
|
type: int
|
||||||
|
default: 64
|
||||||
|
description: |
|
||||||
|
Buffer size of transmit fifo. This used to implement irq_tx_complete.
|
||||||
|
Must be same as Write FIFO: Buffer depth (bytes) in platform designer.
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue