1 /*
2 * Copyright (c) 2017-2023 Intel Corporation
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 /**
8 * @brief UART driver for Intel FPGA UART Core IP
9 * Reference : Embedded Peripherals IP User Guide : 12. JTAG UART Core
10 *
11 */
12
13 #include <zephyr/kernel.h>
14 #include <zephyr/arch/cpu.h>
15 #include <zephyr/drivers/uart.h>
16 #include <zephyr/sys/sys_io.h>
17
18 #include <zephyr/sys/__assert.h>
19
20 #define DT_DRV_COMPAT altr_jtag_uart
21
22 #define UART_ALTERA_JTAG_DATA_OFFSET 0x00 /* DATA : Register offset */
23 #define UART_ALTERA_JTAG_CTRL_OFFSET 0x04 /* CTRL : Register offset */
24 #define UART_IE_TX (1 << 1) /* CTRL : TX Interrupt Enable */
25 #define UART_IE_RX (1 << 0) /* CTRL : RX Interrupt Enable */
26 #define UART_DATA_MASK 0xFF /* DATA : Data Mask */
27 #define UART_WFIFO_MASK 0xFFFF0000 /* CTRL : Transmit FIFO Mask */
28 #define UART_WFIFO_OFST (16)
29
30 #define ALTERA_AVALON_JTAG_UART_DATA_DATA_OFST (0)
31 #define ALTERA_AVALON_JTAG_UART_DATA_RVALID_MSK (0x00008000)
32
33 #define ALTERA_AVALON_JTAG_UART_CONTROL_RI_MSK (0x00000100)
34 #define ALTERA_AVALON_JTAG_UART_CONTROL_WI_MSK (0x00000200)
35
36 #ifdef CONFIG_UART_ALTERA_JTAG_HAL
37 #include "altera_avalon_jtag_uart.h"
38 #include "altera_avalon_jtag_uart_regs.h"
39
40 extern int altera_avalon_jtag_uart_read(altera_avalon_jtag_uart_state *sp,
41 char *buffer, int space, int flags);
42 extern int altera_avalon_jtag_uart_write(altera_avalon_jtag_uart_state *sp,
43 const char *ptr, int count, int flags);
44 #else
45
46 /* device data */
47 struct uart_altera_jtag_device_data {
48 struct k_spinlock lock;
49 #ifdef CONFIG_UART_INTERRUPT_DRIVEN
50 uart_irq_callback_user_data_t cb; /* Callback function pointer */
51 void *cb_data; /* Callback function arg */
52 #endif /* CONFIG_UART_INTERRUPT_DRIVEN */
53 };
54
55 /* device config */
56 struct uart_altera_jtag_device_config {
57 mm_reg_t base;
58 #ifdef CONFIG_UART_INTERRUPT_DRIVEN
59 uart_irq_config_func_t irq_config_func;
60 unsigned int irq_num;
61 uint16_t write_fifo_depth;
62 #endif /* CONFIG_UART_INTERRUPT_DRIVEN */
63 };
64 #endif /* CONFIG_UART_ALTERA_JTAG_HAL */
65
66 #ifndef CONFIG_UART_ALTERA_JTAG_HAL
67 /**
68 * @brief Poll the device for input.
69 *
70 * @param dev UART device instance
71 * @param c Pointer to character
72 *
73 * @return 0 if a character arrived, -1 otherwise.
74 * -EINVAL if c is null pointer.
75 */
uart_altera_jtag_poll_in(const struct device * dev,unsigned char * c)76 static int uart_altera_jtag_poll_in(const struct device *dev,
77 unsigned char *c)
78 {
79 int ret = -1;
80 const struct uart_altera_jtag_device_config *config = dev->config;
81 struct uart_altera_jtag_device_data *data = dev->data;
82 unsigned int input_data;
83
84 /* generate fatal error if CONFIG_ASSERT is enabled. */
85 __ASSERT(c != NULL, "c is null pointer!");
86
87 /* Stop, if c is null pointer */
88 if (c == NULL) {
89 return -EINVAL;
90 }
91
92 k_spinlock_key_t key = k_spin_lock(&data->lock);
93
94 input_data = sys_read32(config->base + UART_ALTERA_JTAG_DATA_OFFSET);
95
96 /* check if data is valid. */
97 if (input_data & ALTERA_AVALON_JTAG_UART_DATA_RVALID_MSK) {
98 *c = (input_data & UART_DATA_MASK) >> ALTERA_AVALON_JTAG_UART_DATA_DATA_OFST;
99 ret = 0;
100 }
101
102 k_spin_unlock(&data->lock, key);
103
104 return ret;
105 }
106 #endif /* CONFIG_UART_ALTERA_JTAG_HAL */
107
108 /**
109 * @brief Output a character in polled mode.
110 *
111 * This routine checks if the transmitter is full.
112 * When the transmitter is not full, it writes a character to the data register.
113 * It waits and blocks the calling thread, otherwise. This function is a blocking call.
114 *
115 * @param dev UART device instance
116 * @param c Character to send
117 */
uart_altera_jtag_poll_out(const struct device * dev,unsigned char c)118 static void uart_altera_jtag_poll_out(const struct device *dev,
119 unsigned char c)
120 {
121 #ifdef CONFIG_UART_ALTERA_JTAG_HAL
122 altera_avalon_jtag_uart_state ustate;
123
124 ustate.base = JTAG_UART_0_BASE;
125 altera_avalon_jtag_uart_write(&ustate, &c, 1, 0);
126 #else
127 const struct uart_altera_jtag_device_config *config = dev->config;
128 struct uart_altera_jtag_device_data *data = dev->data;
129
130 k_spinlock_key_t key = k_spin_lock(&data->lock);
131
132 /* While TX FIFO full */
133 while (!(sys_read32(config->base + UART_ALTERA_JTAG_CTRL_OFFSET) & UART_WFIFO_MASK)) {
134 }
135
136 sys_write8(c, config->base + UART_ALTERA_JTAG_DATA_OFFSET);
137
138 k_spin_unlock(&data->lock, key);
139 #endif /* CONFIG_UART_ALTERA_JTAG_HAL */
140 }
141
142 /**
143 * @brief Initialise an instance of the driver
144 *
145 * This function initialise the interrupt configuration for the driver.
146 *
147 * @param dev UART device instance
148 *
149 * @return 0 to indicate success.
150 */
uart_altera_jtag_init(const struct device * dev)151 static int uart_altera_jtag_init(const struct device *dev)
152 {
153 /*
154 * Work around to clear interrupt enable bits
155 * as it is not being done by HAL driver explicitly.
156 */
157 #ifdef CONFIG_UART_ALTERA_JTAG_HAL
158 IOWR_ALTERA_AVALON_JTAG_UART_CONTROL(JTAG_UART_0_BASE, 0);
159 #else
160 const struct uart_altera_jtag_device_config *config = dev->config;
161 uint32_t ctrl_val = sys_read32(config->base + UART_ALTERA_JTAG_CTRL_OFFSET);
162
163 #ifdef CONFIG_UART_INTERRUPT_DRIVEN
164 /*
165 * Enable hardware interrupt.
166 * The corresponding csr from IP still needs to be set,
167 * so that the IP generates interrupt signal.
168 */
169 config->irq_config_func(dev);
170 #endif
171 /* Disable the tx and rx interrupt signals from JTAG core IP. */
172 ctrl_val &= ~(UART_IE_TX | UART_IE_RX);
173 sys_write32(ctrl_val, config->base + UART_ALTERA_JTAG_CTRL_OFFSET);
174 #endif /* CONFIG_UART_ALTERA_JTAG_HAL */
175 return 0;
176 }
177
178 /*
179 * Functions for Interrupt driven API
180 */
181 #if defined(CONFIG_UART_INTERRUPT_DRIVEN) && !defined(CONFIG_UART_ALTERA_JTAG_HAL)
182
183 /**
184 * @brief Fill FIFO with data
185 * This function is expected to be called from UART interrupt handler (ISR),
186 * if uart_irq_tx_ready() returns true.
187 *
188 * @param dev UART device instance
189 * @param tx_data Data to transmit
190 * @param size Number of bytes to send
191 *
192 * @return Number of bytes sent
193 */
uart_altera_jtag_fifo_fill(const struct device * dev,const uint8_t * tx_data,int size)194 static int uart_altera_jtag_fifo_fill(const struct device *dev,
195 const uint8_t *tx_data,
196 int size)
197 {
198 const struct uart_altera_jtag_device_config *config = dev->config;
199 struct uart_altera_jtag_device_data *data = dev->data;
200 uint32_t ctrl_val;
201 uint32_t space = 0;
202
203 int i;
204
205 /* generate fatal error if CONFIG_ASSERT is enabled. */
206 __ASSERT(tx_data != NULL, "tx buffer is null pointer!");
207
208 /* Stop, if buffer is null pointer */
209 if (tx_data == NULL) {
210 return 0;
211 }
212
213 k_spinlock_key_t key = k_spin_lock(&data->lock);
214
215 ctrl_val = sys_read32(config->base + UART_ALTERA_JTAG_CTRL_OFFSET);
216 space = (ctrl_val & UART_WFIFO_MASK) >> UART_WFIFO_OFST;
217
218 /* guard for tx data overflow:
219 * make sure that driver is not sending more than current available space.
220 */
221 for (i = 0; (i < size) && (i < space); i++) {
222 sys_write8(tx_data[i], config->base + UART_ALTERA_JTAG_DATA_OFFSET);
223 }
224
225 k_spin_unlock(&data->lock, key);
226
227 return i;
228 }
229
230 /**
231 * @brief Read data from FIFO
232 * This function is expected to be called from UART interrupt handler (ISR),
233 * if uart_irq_rx_ready() returns true.
234 *
235 * @param dev UART device instance
236 * @param rx_data Data container
237 * @param size Container size
238 *
239 * @return Number of bytes read
240 */
uart_altera_jtag_fifo_read(const struct device * dev,uint8_t * rx_data,const int size)241 static int uart_altera_jtag_fifo_read(const struct device *dev, uint8_t *rx_data,
242 const int size)
243 {
244 const struct uart_altera_jtag_device_config *config = dev->config;
245 struct uart_altera_jtag_device_data *data = dev->data;
246 int i;
247 unsigned int input_data;
248
249 /* generate fatal error if CONFIG_ASSERT is enabled. */
250 __ASSERT(rx_data != NULL, "Rx buffer is null pointer!");
251
252 /* Stop, if buffer is null pointer */
253 if (rx_data == NULL) {
254 return 0;
255 }
256
257 k_spinlock_key_t key = k_spin_lock(&data->lock);
258
259 for (i = 0; i < size; i++) {
260 input_data = sys_read32(config->base + UART_ALTERA_JTAG_DATA_OFFSET);
261
262 if (input_data & ALTERA_AVALON_JTAG_UART_DATA_RVALID_MSK) {
263 rx_data[i] = (input_data & UART_DATA_MASK) >>
264 ALTERA_AVALON_JTAG_UART_DATA_DATA_OFST;
265 } else {
266 /* break upon invalid data or no more data */
267 break;
268 }
269 }
270
271 k_spin_unlock(&data->lock, key);
272
273 return i;
274 }
275
276 /**
277 * @brief Enable TX interrupt in IER
278 *
279 * @param dev UART device instance
280 */
uart_altera_jtag_irq_tx_enable(const struct device * dev)281 static void uart_altera_jtag_irq_tx_enable(const struct device *dev)
282 {
283 struct uart_altera_jtag_device_data *data = dev->data;
284 const struct uart_altera_jtag_device_config *config = dev->config;
285 uint32_t ctrl_val = sys_read32(config->base + UART_ALTERA_JTAG_CTRL_OFFSET);
286
287 k_spinlock_key_t key = k_spin_lock(&data->lock);
288
289 ctrl_val |= UART_IE_TX;
290 sys_write32(ctrl_val, config->base + UART_ALTERA_JTAG_CTRL_OFFSET);
291
292 k_spin_unlock(&data->lock, key);
293 }
294
295 /**
296 * @brief Disable TX interrupt in IER
297 *
298 * @param dev UART device instance
299 */
uart_altera_jtag_irq_tx_disable(const struct device * dev)300 static void uart_altera_jtag_irq_tx_disable(const struct device *dev)
301 {
302 struct uart_altera_jtag_device_data *data = dev->data;
303 const struct uart_altera_jtag_device_config *config = dev->config;
304 uint32_t ctrl_val = sys_read32(config->base + UART_ALTERA_JTAG_CTRL_OFFSET);
305
306 k_spinlock_key_t key = k_spin_lock(&data->lock);
307
308 ctrl_val &= ~UART_IE_TX;
309 sys_write32(ctrl_val, config->base + UART_ALTERA_JTAG_CTRL_OFFSET);
310
311 k_spin_unlock(&data->lock, key);
312 }
313
314 /**
315 * @brief Check if UART TX buffer can accept a new char.
316 *
317 * @param dev UART device instance
318 *
319 * @return 1 if TX interrupt is enabled and at least one char can be written to UART.
320 * 0 If device is not ready to write a new byte.
321 */
uart_altera_jtag_irq_tx_ready(const struct device * dev)322 static int uart_altera_jtag_irq_tx_ready(const struct device *dev)
323 {
324 struct uart_altera_jtag_device_data *data = dev->data;
325 const struct uart_altera_jtag_device_config *config = dev->config;
326 uint32_t ctrl_val = sys_read32(config->base + UART_ALTERA_JTAG_CTRL_OFFSET);
327 int ret = 0;
328 uint32_t space = 0;
329
330 k_spinlock_key_t key = k_spin_lock(&data->lock);
331
332 /* if TX interrupt is enabled */
333 if (ctrl_val & ALTERA_AVALON_JTAG_UART_CONTROL_WI_MSK) {
334 /* check for space in tx fifo */
335 space = (ctrl_val & UART_WFIFO_MASK) >> UART_WFIFO_OFST;
336 if (space) {
337 ret = 1;
338 }
339 }
340
341 k_spin_unlock(&data->lock, key);
342
343 return ret;
344 }
345
346 /**
347 * @brief Check if nothing remains to be transmitted
348 *
349 * @param dev UART device instance
350 *
351 * @return 1 if nothing remains to be transmitted, 0 otherwise
352 */
uart_altera_jtag_irq_tx_complete(const struct device * dev)353 static int uart_altera_jtag_irq_tx_complete(const struct device *dev)
354 {
355 struct uart_altera_jtag_device_data *data = dev->data;
356 const struct uart_altera_jtag_device_config *config = dev->config;
357 uint32_t ctrl_val = sys_read32(config->base + UART_ALTERA_JTAG_CTRL_OFFSET);
358 int ret = 0;
359 uint32_t space = 0;
360
361 k_spinlock_key_t key = k_spin_lock(&data->lock);
362
363 /* note: This is checked indirectly via the space in tx fifo. */
364 space = (ctrl_val & UART_WFIFO_MASK) >> UART_WFIFO_OFST;
365 if (space == config->write_fifo_depth) {
366 ret = 1;
367 }
368
369 k_spin_unlock(&data->lock, key);
370
371 return ret;
372 }
373
374 /**
375 * @brief Enable RX interrupt in IER
376 *
377 * @param dev UART device instance
378 */
uart_altera_jtag_irq_rx_enable(const struct device * dev)379 static void uart_altera_jtag_irq_rx_enable(const struct device *dev)
380 {
381 struct uart_altera_jtag_device_data *data = dev->data;
382 const struct uart_altera_jtag_device_config *config = dev->config;
383 uint32_t ctrl_val = sys_read32(config->base + UART_ALTERA_JTAG_CTRL_OFFSET);
384
385 k_spinlock_key_t key = k_spin_lock(&data->lock);
386
387 ctrl_val |= UART_IE_RX;
388 sys_write32(ctrl_val, config->base + UART_ALTERA_JTAG_CTRL_OFFSET);
389
390 k_spin_unlock(&data->lock, key);
391 }
392
393 /**
394 * @brief Disable RX interrupt in IER
395 *
396 * @param dev UART device instance
397 */
uart_altera_jtag_irq_rx_disable(const struct device * dev)398 static void uart_altera_jtag_irq_rx_disable(const struct device *dev)
399 {
400 struct uart_altera_jtag_device_data *data = dev->data;
401 const struct uart_altera_jtag_device_config *config = dev->config;
402 uint32_t ctrl_val = sys_read32(config->base + UART_ALTERA_JTAG_CTRL_OFFSET);
403
404 k_spinlock_key_t key = k_spin_lock(&data->lock);
405
406 ctrl_val &= ~UART_IE_RX;
407 sys_write32(ctrl_val, config->base + UART_ALTERA_JTAG_CTRL_OFFSET);
408
409 k_spin_unlock(&data->lock, key);
410 }
411
412 /**
413 * @brief Check if Rx IRQ has been raised
414 *
415 * @param dev UART device instance
416 *
417 * @return 1 if an IRQ is ready, 0 otherwise
418 */
uart_altera_jtag_irq_rx_ready(const struct device * dev)419 static int uart_altera_jtag_irq_rx_ready(const struct device *dev)
420 {
421 struct uart_altera_jtag_device_data *data = dev->data;
422 const struct uart_altera_jtag_device_config *config = dev->config;
423 uint32_t ctrl_val = sys_read32(config->base + UART_ALTERA_JTAG_CTRL_OFFSET);
424 int ret = 0;
425
426 k_spinlock_key_t key = k_spin_lock(&data->lock);
427
428 if (ctrl_val & ALTERA_AVALON_JTAG_UART_CONTROL_RI_MSK) {
429 ret = 1;
430 }
431
432 k_spin_unlock(&data->lock, key);
433
434 return ret;
435 }
436
437 /**
438 * @brief Update cached contents of IIR
439 *
440 * @param dev UART device instance
441 *
442 * @return Always 1
443 */
uart_altera_jtag_irq_update(const struct device * dev)444 static int uart_altera_jtag_irq_update(const struct device *dev)
445 {
446 return 1;
447 }
448
449 /**
450 * @brief Check if any IRQ is pending
451 *
452 * @param dev UART device instance
453 *
454 * @return 1 if an IRQ is pending, 0 otherwise
455 */
uart_altera_jtag_irq_is_pending(const struct device * dev)456 static int uart_altera_jtag_irq_is_pending(const struct device *dev)
457 {
458 struct uart_altera_jtag_device_data *data = dev->data;
459 k_spinlock_key_t key = k_spin_lock(&data->lock);
460 const struct uart_altera_jtag_device_config *config = dev->config;
461 uint32_t ctrl_val = sys_read32(config->base + UART_ALTERA_JTAG_CTRL_OFFSET);
462 int ret = 0;
463
464 if (ctrl_val &
465 (ALTERA_AVALON_JTAG_UART_CONTROL_RI_MSK|ALTERA_AVALON_JTAG_UART_CONTROL_WI_MSK)) {
466 ret = 1;
467 }
468
469 k_spin_unlock(&data->lock, key);
470
471 return ret;
472 }
473
474 /**
475 * @brief Set the callback function pointer for IRQ.
476 *
477 * @param dev UART device instance
478 * @param cb Callback function pointer.
479 * @param cb_data Data to pass to callback function.
480 */
uart_altera_jtag_irq_callback_set(const struct device * dev,uart_irq_callback_user_data_t cb,void * cb_data)481 static void uart_altera_jtag_irq_callback_set(const struct device *dev,
482 uart_irq_callback_user_data_t cb,
483 void *cb_data)
484 {
485 struct uart_altera_jtag_device_data *data = dev->data;
486
487 /* generate fatal error if CONFIG_ASSERT is enabled. */
488 __ASSERT(cb != NULL, "uart_irq_callback_user_data_t cb is null pointer!");
489
490 k_spinlock_key_t key = k_spin_lock(&data->lock);
491
492 data->cb = cb;
493 data->cb_data = cb_data;
494
495 k_spin_unlock(&data->lock, key);
496 }
497
498 /**
499 * @brief Interrupt service routine.
500 *
501 * This simply calls the callback function, if one exists.
502 *
503 * @param dev Pointer to UART device struct
504 */
uart_altera_jtag_isr(const struct device * dev)505 static void uart_altera_jtag_isr(const struct device *dev)
506 {
507 struct uart_altera_jtag_device_data *data = dev->data;
508 uart_irq_callback_user_data_t callback = data->cb;
509
510 if (callback) {
511 callback(dev, data->cb_data);
512 }
513 }
514
515 #endif /* CONFIG_UART_INTERRUPT_DRIVEN && !CONFIG_UART_ALTERA_JTAG_HAL */
516
517 static DEVICE_API(uart, uart_altera_jtag_driver_api) = {
518 #ifndef CONFIG_UART_ALTERA_JTAG_HAL
519 .poll_in = uart_altera_jtag_poll_in,
520 #endif /* CONFIG_UART_ALTERA_JTAG_HAL */
521 .poll_out = uart_altera_jtag_poll_out,
522 .err_check = NULL,
523 #if defined(CONFIG_UART_INTERRUPT_DRIVEN) && !defined(CONFIG_UART_ALTERA_JTAG_HAL)
524 .fifo_fill = uart_altera_jtag_fifo_fill,
525 .fifo_read = uart_altera_jtag_fifo_read,
526 .irq_tx_enable = uart_altera_jtag_irq_tx_enable,
527 .irq_tx_disable = uart_altera_jtag_irq_tx_disable,
528 .irq_tx_ready = uart_altera_jtag_irq_tx_ready,
529 .irq_tx_complete = uart_altera_jtag_irq_tx_complete,
530 .irq_rx_enable = uart_altera_jtag_irq_rx_enable,
531 .irq_rx_disable = uart_altera_jtag_irq_rx_disable,
532 .irq_rx_ready = uart_altera_jtag_irq_rx_ready,
533 .irq_is_pending = uart_altera_jtag_irq_is_pending,
534 .irq_update = uart_altera_jtag_irq_update,
535 .irq_callback_set = uart_altera_jtag_irq_callback_set,
536 #endif /* CONFIG_UART_INTERRUPT_DRIVEN && !CONFIG_UART_ALTERA_JTAG_HAL */
537 };
538
539 #ifdef CONFIG_UART_ALTERA_JTAG_HAL
540 #define UART_ALTERA_JTAG_DEVICE_INIT(n) \
541 DEVICE_DT_INST_DEFINE(n, uart_altera_jtag_init, NULL, NULL, NULL, PRE_KERNEL_1, \
542 CONFIG_SERIAL_INIT_PRIORITY, \
543 &uart_altera_jtag_driver_api);
544 #else
545
546 #ifdef CONFIG_UART_INTERRUPT_DRIVEN
547 #define UART_ALTERA_JTAG_CONFIG_FUNC(n) \
548 static void uart_altera_jtag_irq_config_func_##n(const struct device *dev) \
549 { \
550 IRQ_CONNECT(DT_INST_IRQN(n), \
551 DT_INST_IRQ(n, priority), \
552 uart_altera_jtag_isr, \
553 DEVICE_DT_INST_GET(n), 0); \
554 \
555 irq_enable(DT_INST_IRQN(n)); \
556 }
557
558 #define UART_ALTERA_JTAG_CONFIG_INIT(n) \
559 .irq_config_func = uart_altera_jtag_irq_config_func_##n, \
560 .irq_num = DT_INST_IRQN(n), \
561 .write_fifo_depth = DT_INST_PROP_OR(n, write_fifo_depth, 0),\
562
563 #else
564 #define UART_ALTERA_JTAG_CONFIG_FUNC(n)
565 #define UART_ALTERA_JTAG_CONFIG_INIT(n)
566 #define UART_ALTERA_JTAG_DATA_INIT(n)
567 #endif /* CONFIG_UART_INTERRUPT_DRIVEN */
568
569 #define UART_ALTERA_JTAG_DEVICE_INIT(n) \
570 UART_ALTERA_JTAG_CONFIG_FUNC(n) \
571 static struct uart_altera_jtag_device_data uart_altera_jtag_device_data_##n = { \
572 }; \
573 \
574 static const struct uart_altera_jtag_device_config uart_altera_jtag_dev_cfg_##n = { \
575 .base = DT_INST_REG_ADDR(n), \
576 UART_ALTERA_JTAG_CONFIG_INIT(n) \
577 }; \
578 DEVICE_DT_INST_DEFINE(n, \
579 uart_altera_jtag_init, \
580 NULL, \
581 &uart_altera_jtag_device_data_##n, \
582 &uart_altera_jtag_dev_cfg_##n, \
583 PRE_KERNEL_1, \
584 CONFIG_SERIAL_INIT_PRIORITY, \
585 &uart_altera_jtag_driver_api);
586 #endif /* CONFIG_UART_ALTERA_JTAG_HAL */
587
588 DT_INST_FOREACH_STATUS_OKAY(UART_ALTERA_JTAG_DEVICE_INIT)
589