Skip to content

Commit df5ffc9

Browse files
robhancocksedkartben
authored andcommitted
drivers: serial: uart_xlnx_ps: Fix interrupt mode issues
This driver had some issues with interrupt-driven operation, which manifested by the console breaking when enabling the Zephyr shell on the kv260_r5 target for example. Fixed the following: -Ensure device is fully hardware reset during initialization -Changed poll_out to be more consistent with other drivers, i.e. only wait for the UART to accept the character, not for it to be fully transmitted. -Added implementation for err_check function, as otherwise there was no way to detect or clear the error interrupts enabled by irq_err_enable. -Fixed logic for enabling/disabling interrupts. This should only be done by explicit enable/disable calls, not as part of fifo_fill etc. -This hardware does not produce interrupts for TX FIFO empty or RX FIFO threshold when enabling them if the TX FIFO is already empty or RX FIFO already contains data. When enabling interrupts in these cases, use a timer to trigger a user callback to match the normal UART API usage, similar to the xlnx_uartlite driver. -Other minor cleanups to interrupt-driven functions. Signed-off-by: Robert Hancock <robert.hancock@calian.com>
1 parent a52230b commit df5ffc9

File tree

1 file changed

+119
-42
lines changed

1 file changed

+119
-42
lines changed

drivers/serial/uart_xlnx_ps.c

Lines changed: 119 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -158,6 +158,8 @@ struct uart_xlnx_ps_dev_data_t {
158158
uint32_t flowctrl;
159159

160160
#ifdef CONFIG_UART_INTERRUPT_DRIVEN
161+
const struct device *dev;
162+
struct k_timer timer;
161163
uart_irq_callback_user_data_t user_cb;
162164
void *user_data;
163165
#endif
@@ -270,6 +272,25 @@ static void set_baudrate(const struct device *dev, uint32_t baud_rate)
270272
}
271273
}
272274

275+
#ifdef CONFIG_UART_INTERRUPT_DRIVEN
276+
277+
/**
278+
* @brief Trigger a UART callback based on a timer.
279+
*
280+
* @param timer Timer that triggered the callback
281+
*/
282+
static void uart_xlnx_ps_soft_isr(struct k_timer *timer)
283+
{
284+
struct uart_xlnx_ps_dev_data_t *data =
285+
CONTAINER_OF(timer, struct uart_xlnx_ps_dev_data_t, timer);
286+
287+
if (data->user_cb) {
288+
data->user_cb(data->dev, data->user_data);
289+
}
290+
}
291+
292+
#endif
293+
273294
/**
274295
* @brief Initialize individual UART port
275296
*
@@ -290,16 +311,18 @@ static int uart_xlnx_ps_init(const struct device *dev)
290311
DEVICE_MMIO_MAP(dev, K_MEM_CACHE_NONE);
291312
uintptr_t reg_base = DEVICE_MMIO_GET(dev);
292313

293-
/* Disable RX/TX before changing any configuration data */
294-
xlnx_ps_disable_uart(reg_base);
295-
296314
#ifdef CONFIG_PINCTRL
297315
err = pinctrl_apply_state(dev_cfg->pincfg, PINCTRL_STATE_DEFAULT);
298316
if (err < 0) {
299317
return err;
300318
}
301319
#endif
302320

321+
/* Set RX/TX reset and disable RX/TX */
322+
sys_write32(XUARTPS_CR_STOPBRK | XUARTPS_CR_TX_DIS | XUARTPS_CR_RX_DIS | XUARTPS_CR_TXRST |
323+
XUARTPS_CR_RXRST,
324+
reg_base + XUARTPS_CR_OFFSET);
325+
303326
/* Set initial character length / start/stop bit / parity configuration */
304327
reg_val = sys_read32(reg_base + XUARTPS_MR_OFFSET);
305328
reg_val &= (~(XUARTPS_MR_CHARLEN_MASK | XUARTPS_MR_STOPMODE_MASK | XUARTPS_MR_PARITY_MASK));
@@ -316,10 +339,14 @@ static int uart_xlnx_ps_init(const struct device *dev)
316339
set_baudrate(dev, dev_cfg->baud_rate);
317340

318341
#ifdef CONFIG_UART_INTERRUPT_DRIVEN
342+
struct uart_xlnx_ps_dev_data_t *dev_data = dev->data;
319343

320344
/* Clear any pending interrupt flags */
321345
sys_write32(XUARTPS_IXR_MASK, reg_base + XUARTPS_ISR_OFFSET);
322346

347+
dev_data->dev = dev;
348+
k_timer_init(&dev_data->timer, &uart_xlnx_ps_soft_isr, NULL);
349+
323350
/* Attach to & unmask the corresponding interrupt vector */
324351
dev_cfg->irq_config_func(dev);
325352

@@ -354,7 +381,7 @@ static int uart_xlnx_ps_poll_in(const struct device *dev, unsigned char *c)
354381
/**
355382
* @brief Output a character in polled mode.
356383
*
357-
* Checks if the transmitter is empty. If empty, a character is written to
384+
* Checks if the transmitter has available TX FIFO space. If so, a character is written to
358385
* the data register.
359386
*
360387
* If the hardware flow control is enabled then the handshake signal CTS has to
@@ -368,18 +395,54 @@ static int uart_xlnx_ps_poll_in(const struct device *dev, unsigned char *c)
368395
static void uart_xlnx_ps_poll_out(const struct device *dev, unsigned char c)
369396
{
370397
uintptr_t reg_base = DEVICE_MMIO_GET(dev);
371-
uint32_t reg_val;
372398

373-
/* wait for transmitter to ready to accept a character */
374-
do {
375-
reg_val = sys_read32(reg_base + XUARTPS_SR_OFFSET);
376-
} while ((reg_val & XUARTPS_SR_TXEMPTY) == 0);
399+
/* wait for transmitter to be ready to accept a character */
400+
while ((sys_read32(reg_base + XUARTPS_SR_OFFSET) & XUARTPS_SR_TXFULL) != 0) {
401+
}
377402

378403
sys_write32((uint32_t)(c & 0xFF), reg_base + XUARTPS_FIFO_OFFSET);
404+
}
405+
406+
/**
407+
* Check for pending TX/TX errors on the port.
408+
*
409+
* @param dev UART device struct
410+
* @return 0 if no errors, UART_ERROR_* flags otherwise
411+
*/
412+
static int uart_xlnx_ps_err_check(const struct device *dev)
413+
{
414+
uintptr_t reg_base = DEVICE_MMIO_GET(dev);
415+
uint32_t reg_val = sys_read32(reg_base + XUARTPS_ISR_OFFSET);
416+
int err = 0;
417+
418+
if (reg_val & XUARTPS_IXR_RBRK) {
419+
err |= UART_BREAK;
420+
}
379421

380-
do {
381-
reg_val = sys_read32(reg_base + XUARTPS_SR_OFFSET);
382-
} while ((reg_val & XUARTPS_SR_TXEMPTY) == 0);
422+
if (reg_val & XUARTPS_IXR_TOVR) {
423+
err |= UART_ERROR_OVERRUN;
424+
}
425+
426+
if (reg_val & XUARTPS_IXR_TOUT) {
427+
err |= UART_ERROR_NOISE;
428+
}
429+
430+
if (reg_val & XUARTPS_IXR_PARITY) {
431+
err |= UART_ERROR_PARITY;
432+
}
433+
434+
if (reg_val & XUARTPS_IXR_FRAMING) {
435+
err |= UART_ERROR_FRAMING;
436+
}
437+
438+
if (reg_val & XUARTPS_IXR_RXOVR) {
439+
err |= UART_ERROR_OVERRUN;
440+
}
441+
sys_write32(reg_val & (XUARTPS_IXR_RBRK | XUARTPS_IXR_TOVR | XUARTPS_IXR_TOUT |
442+
XUARTPS_IXR_PARITY | XUARTPS_IXR_FRAMING | XUARTPS_IXR_RXOVR),
443+
reg_base + XUARTPS_ISR_OFFSET);
444+
445+
return err;
383446
}
384447

385448
/**
@@ -826,17 +889,14 @@ static int uart_xlnx_ps_config_get(const struct device *dev, struct uart_config
826889
static int uart_xlnx_ps_fifo_fill(const struct device *dev, const uint8_t *tx_data, int size)
827890
{
828891
uintptr_t reg_base = DEVICE_MMIO_GET(dev);
829-
uint32_t data_iter = 0;
892+
int count = 0;
830893

831-
sys_write32(XUARTPS_IXR_TXEMPTY, reg_base + XUARTPS_IDR_OFFSET);
832-
while (size--) {
833-
while ((sys_read32(reg_base + XUARTPS_SR_OFFSET) & XUARTPS_SR_TXFULL) != 0) {
834-
}
835-
sys_write32((uint32_t)tx_data[data_iter++], reg_base + XUARTPS_FIFO_OFFSET);
894+
while (count < size &&
895+
(sys_read32(reg_base + XUARTPS_SR_OFFSET) & XUARTPS_SR_TXFULL) == 0) {
896+
sys_write32((uint32_t)tx_data[count++], reg_base + XUARTPS_FIFO_OFFSET);
836897
}
837-
sys_write32(XUARTPS_IXR_TXEMPTY, reg_base + XUARTPS_IER_OFFSET);
838898

839-
return data_iter;
899+
return count;
840900
}
841901

842902
/**
@@ -851,16 +911,14 @@ static int uart_xlnx_ps_fifo_fill(const struct device *dev, const uint8_t *tx_da
851911
static int uart_xlnx_ps_fifo_read(const struct device *dev, uint8_t *rx_data, const int size)
852912
{
853913
uintptr_t reg_base = DEVICE_MMIO_GET(dev);
854-
uint32_t reg_val = sys_read32(reg_base + XUARTPS_SR_OFFSET);
855-
int inum = 0;
914+
int count = 0;
856915

857-
while (inum < size && (reg_val & XUARTPS_SR_RXEMPTY) == 0) {
858-
rx_data[inum] = (uint8_t)sys_read32(reg_base + XUARTPS_FIFO_OFFSET);
859-
inum++;
860-
reg_val = sys_read32(reg_base + XUARTPS_SR_OFFSET);
916+
while (count < size &&
917+
(sys_read32(reg_base + XUARTPS_SR_OFFSET) & XUARTPS_SR_RXEMPTY) == 0) {
918+
rx_data[count++] = (uint8_t)sys_read32(reg_base + XUARTPS_FIFO_OFFSET);
861919
}
862920

863-
return inum;
921+
return count;
864922
}
865923

866924
/**
@@ -870,9 +928,20 @@ static int uart_xlnx_ps_fifo_read(const struct device *dev, uint8_t *rx_data, co
870928
*/
871929
static void uart_xlnx_ps_irq_tx_enable(const struct device *dev)
872930
{
931+
struct uart_xlnx_ps_dev_data_t *dev_data = dev->data;
873932
uintptr_t reg_base = DEVICE_MMIO_GET(dev);
874933

875934
sys_write32((XUARTPS_IXR_TTRIG | XUARTPS_IXR_TXEMPTY), reg_base + XUARTPS_IER_OFFSET);
935+
if ((sys_read32(reg_base + XUARTPS_SR_OFFSET) & (XUARTPS_SR_TTRIG | XUARTPS_SR_TXEMPTY)) !=
936+
0) {
937+
/*
938+
* Enabling TX empty interrupts does not cause an interrupt
939+
* if the FIFO is already empty.
940+
* Generate a soft interrupt and have it call the
941+
* callback function in timer isr context.
942+
*/
943+
k_timer_start(&dev_data->timer, K_NO_WAIT, K_NO_WAIT);
944+
}
876945
}
877946

878947
/**
@@ -918,11 +987,7 @@ static int uart_xlnx_ps_irq_tx_complete(const struct device *dev)
918987
uintptr_t reg_base = DEVICE_MMIO_GET(dev);
919988
uint32_t reg_val = sys_read32(reg_base + XUARTPS_SR_OFFSET);
920989

921-
if ((reg_val & XUARTPS_SR_TXEMPTY) == 0) {
922-
return 0;
923-
} else {
924-
return 1;
925-
}
990+
return (reg_val & XUARTPS_SR_TXEMPTY) != 0;
926991
}
927992

928993
/**
@@ -932,9 +997,19 @@ static int uart_xlnx_ps_irq_tx_complete(const struct device *dev)
932997
*/
933998
static void uart_xlnx_ps_irq_rx_enable(const struct device *dev)
934999
{
1000+
struct uart_xlnx_ps_dev_data_t *dev_data = dev->data;
9351001
uintptr_t reg_base = DEVICE_MMIO_GET(dev);
9361002

9371003
sys_write32(XUARTPS_IXR_RTRIG, reg_base + XUARTPS_IER_OFFSET);
1004+
if ((sys_read32(reg_base + XUARTPS_SR_OFFSET) & XUARTPS_SR_RXEMPTY) == 0) {
1005+
/*
1006+
* Enabling RX trigger interrupts does not cause an interrupt
1007+
* if the FIFO already contains RX data.
1008+
* Generate a soft interrupt and have it call the
1009+
* callback function in timer isr context.
1010+
*/
1011+
k_timer_start(&dev_data->timer, K_NO_WAIT, K_NO_WAIT);
1012+
}
9381013
}
9391014

9401015
/**
@@ -959,14 +1034,9 @@ static void uart_xlnx_ps_irq_rx_disable(const struct device *dev)
9591034
static int uart_xlnx_ps_irq_rx_ready(const struct device *dev)
9601035
{
9611036
uintptr_t reg_base = DEVICE_MMIO_GET(dev);
962-
uint32_t reg_val = sys_read32(reg_base + XUARTPS_ISR_OFFSET);
1037+
uint32_t reg_val = sys_read32(reg_base + XUARTPS_SR_OFFSET);
9631038

964-
if ((reg_val & XUARTPS_IXR_RTRIG) == 0) {
965-
return 0;
966-
} else {
967-
sys_write32(XUARTPS_IXR_RTRIG, reg_base + XUARTPS_ISR_OFFSET);
968-
return 1;
969-
}
1039+
return (reg_val & XUARTPS_SR_RXEMPTY) == 0;
9701040
}
9711041

9721042
/**
@@ -978,7 +1048,8 @@ static void uart_xlnx_ps_irq_err_enable(const struct device *dev)
9781048
{
9791049
uintptr_t reg_base = DEVICE_MMIO_GET(dev);
9801050

981-
sys_write32(XUARTPS_IXR_TOVR /* [12] Transmitter FIFO Overflow */
1051+
sys_write32(XUARTPS_IXR_RBRK /* [13] Receiver Break */
1052+
| XUARTPS_IXR_TOVR /* [12] Transmitter FIFO Overflow */
9821053
| XUARTPS_IXR_TOUT /* [8] Receiver Timerout */
9831054
| XUARTPS_IXR_PARITY /* [7] Parity Error */
9841055
| XUARTPS_IXR_FRAMING /* [6] Receiver Framing Error */
@@ -997,7 +1068,8 @@ static void uart_xlnx_ps_irq_err_disable(const struct device *dev)
9971068
{
9981069
uintptr_t reg_base = DEVICE_MMIO_GET(dev);
9991070

1000-
sys_write32(XUARTPS_IXR_TOVR /* [12] Transmitter FIFO Overflow */
1071+
sys_write32(XUARTPS_IXR_RBRK /* [13] Receiver Break */
1072+
| XUARTPS_IXR_TOVR /* [12] Transmitter FIFO Overflow */
10011073
| XUARTPS_IXR_TOUT /* [8] Receiver Timerout */
10021074
| XUARTPS_IXR_PARITY /* [7] Parity Error */
10031075
| XUARTPS_IXR_FRAMING /* [6] Receiver Framing Error */
@@ -1034,7 +1106,11 @@ static int uart_xlnx_ps_irq_is_pending(const struct device *dev)
10341106
*/
10351107
static int uart_xlnx_ps_irq_update(const struct device *dev)
10361108
{
1037-
ARG_UNUSED(dev);
1109+
uintptr_t reg_base = DEVICE_MMIO_GET(dev);
1110+
1111+
/* Clear RX/TX interrupts */
1112+
sys_write32(XUARTPS_IXR_TTRIG | XUARTPS_IXR_TXEMPTY | XUARTPS_IXR_RTRIG,
1113+
reg_base + XUARTPS_ISR_OFFSET);
10381114
return 1;
10391115
}
10401116

@@ -1073,6 +1149,7 @@ static void uart_xlnx_ps_isr(const struct device *dev)
10731149
static DEVICE_API(uart, uart_xlnx_ps_driver_api) = {
10741150
.poll_in = uart_xlnx_ps_poll_in,
10751151
.poll_out = uart_xlnx_ps_poll_out,
1152+
.err_check = uart_xlnx_ps_err_check,
10761153
#ifdef CONFIG_UART_USE_RUNTIME_CONFIGURE
10771154
.configure = uart_xlnx_ps_configure,
10781155
.config_get = uart_xlnx_ps_config_get,

0 commit comments

Comments
 (0)