1 /*
2 * Copyright (c) 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 : 11. UART Core
10 * Limitations:
11 * 1. User should consider to always use polling mode, as IP core does not have fifo.
12 * So IP can only send/receive 1 character at a time.
13 * 2. CTS and RTS is purely software controlled. Assertion might not be on time.
14 * 3. Full duplex mode is not supported.
15 */
16
17 #define DT_DRV_COMPAT altr_uart
18
19 #include <zephyr/kernel.h>
20 #include <zephyr/drivers/uart.h>
21
22 #include <zephyr/drivers/serial/uart_altera.h>
23
24 #ifdef CONFIG_UART_LINE_CTRL
25 #ifndef CONFIG_UART_INTERRUPT_DRIVEN
26 /* CTS and RTS is purely software controlled. */
27 #error "uart_altera.c: Must enable UART_INTERRUPT_DRIVEN for line control!"
28 #endif
29 #endif
30
31 /* register offsets */
32 #define ALTERA_AVALON_UART_OFFSET (0x4)
33
34 #define ALTERA_AVALON_UART_RXDATA_REG_OFFSET (0 * ALTERA_AVALON_UART_OFFSET)
35 #define ALTERA_AVALON_UART_TXDATA_REG_OFFSET (1 * ALTERA_AVALON_UART_OFFSET)
36 #define ALTERA_AVALON_UART_STATUS_REG_OFFSET (2 * ALTERA_AVALON_UART_OFFSET)
37 #define ALTERA_AVALON_UART_CONTROL_REG_OFFSET (3 * ALTERA_AVALON_UART_OFFSET)
38 #define ALTERA_AVALON_UART_DIVISOR_REG_OFFSET (4 * ALTERA_AVALON_UART_OFFSET)
39 #define ALTERA_AVALON_UART_EOP_REG_OFFSET (5 * ALTERA_AVALON_UART_OFFSET)
40
41 /*status register mask */
42 #define ALTERA_AVALON_UART_STATUS_PE_MSK (0x1)
43 #define ALTERA_AVALON_UART_STATUS_FE_MSK (0x2)
44 #define ALTERA_AVALON_UART_STATUS_BRK_MSK (0x4)
45 #define ALTERA_AVALON_UART_STATUS_ROE_MSK (0x8)
46 #define ALTERA_AVALON_UART_STATUS_TMT_MSK (0x20)
47 #define ALTERA_AVALON_UART_STATUS_TRDY_MSK (0x40)
48 #define ALTERA_AVALON_UART_STATUS_RRDY_MSK (0x80)
49 #define ALTERA_AVALON_UART_STATUS_DCTS_MSK (0x400)
50 #define ALTERA_AVALON_UART_STATUS_CTS_MSK (0x800)
51 #define ALTERA_AVALON_UART_STATUS_E_MSK (0x100)
52 #define ALTERA_AVALON_UART_STATUS_EOP_MSK (0x1000)
53
54 /* control register mask */
55 #define ALTERA_AVALON_UART_CONTROL_TMT_MSK (0x20)
56 #define ALTERA_AVALON_UART_CONTROL_TRDY_MSK (0x40)
57 #define ALTERA_AVALON_UART_CONTROL_RRDY_MSK (0x80)
58 #define ALTERA_AVALON_UART_CONTROL_E_MSK (0x100)
59 #define ALTERA_AVALON_UART_CONTROL_DCTS_MSK (0x400)
60 #define ALTERA_AVALON_UART_CONTROL_RTS_MSK (0x800)
61 #define ALTERA_AVALON_UART_CONTROL_EOP_MSK (0x1000)
62
63 /* defined values */
64 #define UART_ALTERA_NO_ERROR (0u)
65 #define ALTERA_AVALON_UART_CLEAR_STATUS_VAL (0u)
66 #define ALTERA_AVALON_UART_PENDING_MASK (ALTERA_AVALON_UART_STATUS_RRDY_MSK | \
67 ALTERA_AVALON_UART_STATUS_TRDY_MSK | ALTERA_AVALON_UART_STATUS_E_MSK | \
68 ALTERA_AVALON_UART_STATUS_EOP_MSK)
69
70 /***********************/
71 /* configuration flags */
72 /*
73 * The value ALT_AVALON_UART_FB is a value set in the devices flag field to
74 * indicate that the device has a fixed baud rate; i.e. if this flag is set
75 * software can not control the baud rate of the device.
76 */
77 #define ALT_AVALON_UART_FB 0x1
78
79 /*
80 * The value ALT_AVALON_UART_FC is a value set in the device flag field to
81 * indicate the device is using flow control, i.e. the driver must
82 * throttle on transmit if the nCTS pin is low.
83 */
84 #define ALT_AVALON_UART_FC 0x2
85
86 /* end of configuration flags */
87 /******************************/
88
89 /* device data */
90 struct uart_altera_device_data {
91 struct uart_config uart_cfg; /* stores uart config from device tree*/
92 struct k_spinlock lock;
93 uint32_t status_act; /* stores value of status register. */
94 #ifdef CONFIG_UART_INTERRUPT_DRIVEN
95 uart_irq_callback_user_data_t cb; /**< Callback function pointer */
96 void *cb_data; /**< Callback function arg */
97 #ifdef CONFIG_UART_ALTERA_EOP
98 uint8_t set_eop_cb;
99 uart_irq_callback_user_data_t cb_eop; /**< Callback function pointer */
100 void *cb_data_eop; /**< Callback function arg */
101 #endif /* CONFIG_UART_ALTERA_EOP */
102 #ifdef CONFIG_UART_ALTERA_LINE_CTRL_WORKAROUND
103 uint8_t dcts_rising;
104 #endif /*CONFIG_UART_ALTERA_LINE_CTRL_WORKAROUND*/
105 uint32_t control_val; /* stores value to set control register. */
106 #endif /* CONFIG_UART_INTERRUPT_DRIVEN */
107 };
108
109 /*
110 * device config:
111 * stores data that cannot be changed during run time.
112 */
113 struct uart_altera_device_config {
114 mm_reg_t base;
115 uint32_t flags; /* refer to configuration flags */
116 #ifdef CONFIG_UART_INTERRUPT_DRIVEN
117 uart_irq_config_func_t irq_config_func;
118 unsigned int irq_num;
119 #endif /* CONFIG_UART_INTERRUPT_DRIVEN */
120 };
121
122 #ifdef CONFIG_UART_INTERRUPT_DRIVEN
123 /**
124 * function prototypes
125 */
126 static int uart_altera_irq_update(const struct device *dev);
127 static int uart_altera_irq_tx_ready(const struct device *dev);
128 static int uart_altera_irq_rx_ready(const struct device *dev);
129 #endif /* CONFIG_UART_INTERRUPT_DRIVEN */
130
131 /**
132 * @brief Poll the device for input.
133 *
134 * This is a non-blocking function.
135 *
136 * @param dev UART device instance
137 * @param p_char Pointer to character
138 *
139 * @return 0 if a character arrived, -1 if input buffer is empty.
140 * -EINVAL if p_char is null pointer
141 */
uart_altera_poll_in(const struct device * dev,unsigned char * p_char)142 static int uart_altera_poll_in(const struct device *dev, unsigned char *p_char)
143 {
144 const struct uart_altera_device_config *config = dev->config;
145 struct uart_altera_device_data *data = dev->data;
146 int ret_val = -1;
147 uint32_t status;
148
149 /* generate fatal error if CONFIG_ASSERT is enabled. */
150 __ASSERT(p_char != NULL, "p_char is null pointer!");
151
152 /* Stop, if p_char is null pointer */
153 if (p_char == NULL) {
154 return -EINVAL;
155 }
156
157 k_spinlock_key_t key = k_spin_lock(&data->lock);
158
159 /* check if received character is ready.*/
160 status = sys_read32(config->base + ALTERA_AVALON_UART_STATUS_REG_OFFSET);
161 if (status & ALTERA_AVALON_UART_STATUS_RRDY_MSK) {
162 /* got a character */
163 *p_char = sys_read32(config->base + ALTERA_AVALON_UART_RXDATA_REG_OFFSET);
164 ret_val = 0;
165 }
166
167 k_spin_unlock(&data->lock, key);
168
169 return ret_val;
170 }
171
172 /**
173 * @brief Output a character in polled mode.
174 *
175 * This function will block until transmitter is ready.
176 * Then, a character will be transmitted.
177 *
178 * @param dev UART device instance
179 * @param c Character to send
180 */
uart_altera_poll_out(const struct device * dev,unsigned char c)181 static void uart_altera_poll_out(const struct device *dev, unsigned char c)
182 {
183 const struct uart_altera_device_config *config = dev->config;
184 struct uart_altera_device_data *data = dev->data;
185 uint32_t status;
186
187 k_spinlock_key_t key = k_spin_lock(&data->lock);
188
189 do {
190 /* wait until uart is free to transmit.*/
191 status = sys_read32(config->base + ALTERA_AVALON_UART_STATUS_REG_OFFSET);
192 } while ((status & ALTERA_AVALON_UART_STATUS_TRDY_MSK) == 0);
193
194 sys_write32(c, config->base + ALTERA_AVALON_UART_TXDATA_REG_OFFSET);
195
196 k_spin_unlock(&data->lock, key);
197 }
198
199 /**
200 * @brief Initialise an instance of the driver
201 *
202 * This function initialise the interrupt configuration for the driver.
203 *
204 * @param dev UART device instance
205 *
206 * @return 0 to indicate success.
207 */
uart_altera_init(const struct device * dev)208 static int uart_altera_init(const struct device *dev)
209 {
210 #ifdef CONFIG_UART_INTERRUPT_DRIVEN
211 struct uart_altera_device_data *data = dev->data;
212 const struct uart_altera_device_config *config = dev->config;
213 /* clear status to ensure, that interrupts are not triggered due to old status. */
214 sys_write32(ALTERA_AVALON_UART_CLEAR_STATUS_VAL, config->base
215 + ALTERA_AVALON_UART_STATUS_REG_OFFSET);
216
217 /*
218 * Enable hardware interrupt.
219 * The corresponding csr from IP still needs to be set,
220 * so that the IP generates interrupt signal.
221 */
222 config->irq_config_func(dev);
223
224 #ifdef CONFIG_UART_LINE_CTRL
225 /* Enable DCTS interrupt. */
226 data->control_val = ALTERA_AVALON_UART_CONTROL_DCTS_MSK;
227 #endif /* CONFIG_UART_LINE_CTRL */
228
229 sys_write32(data->control_val, config->base + ALTERA_AVALON_UART_CONTROL_REG_OFFSET);
230
231 #endif /* CONFIG_UART_INTERRUPT_DRIVEN */
232
233 return 0;
234 }
235
236 /**
237 * @brief Check if an error was received
238 * If error is received, it will be mapped to uart_rx_stop_reason.
239 * This function should be called after irq_update.
240 * If interrupt driven API is not enabled,
241 * this function will read and clear the status register.
242 *
243 * @param dev UART device struct
244 *
245 * @return UART_ERROR_OVERRUN, UART_ERROR_PARITY, UART_ERROR_FRAMING,
246 * UART_BREAK if an error was detected, 0 otherwise.
247 */
uart_altera_err_check(const struct device * dev)248 static int uart_altera_err_check(const struct device *dev)
249 {
250 struct uart_altera_device_data *data = dev->data;
251 int err = UART_ALTERA_NO_ERROR;
252
253 #ifndef CONFIG_UART_INTERRUPT_DRIVEN
254 const struct uart_altera_device_config *config = dev->config;
255 k_spinlock_key_t key = k_spin_lock(&data->lock);
256
257 data->status_act = sys_read32(config->base + ALTERA_AVALON_UART_STATUS_REG_OFFSET);
258 #endif
259
260 if (data->status_act & ALTERA_AVALON_UART_STATUS_E_MSK) {
261 if (data->status_act & ALTERA_AVALON_UART_STATUS_PE_MSK) {
262 err |= UART_ERROR_PARITY;
263 }
264
265 if (data->status_act & ALTERA_AVALON_UART_STATUS_FE_MSK) {
266 err |= UART_ERROR_FRAMING;
267 }
268
269 if (data->status_act & ALTERA_AVALON_UART_STATUS_BRK_MSK) {
270 err |= UART_BREAK;
271 }
272
273 if (data->status_act & ALTERA_AVALON_UART_STATUS_ROE_MSK) {
274 err |= UART_ERROR_OVERRUN;
275 }
276 }
277
278 #ifndef CONFIG_UART_INTERRUPT_DRIVEN
279 /* clear status */
280 sys_write32(ALTERA_AVALON_UART_CLEAR_STATUS_VAL, config->base
281 + ALTERA_AVALON_UART_STATUS_REG_OFFSET);
282 k_spin_unlock(&data->lock, key);
283 #endif
284
285 return err;
286 }
287
288 #ifdef CONFIG_UART_USE_RUNTIME_CONFIGURE
289 /***
290 * @brief helper function to check, if the configuration is support.
291 * @param cfg_stored : The original configuration.
292 * @param cfg_in : The input configuration.
293 * @return true if only baudrate is changed. otherwise false.
294 */
uart_altera_check_configuration(const struct uart_config * cfg_stored,const struct uart_config * cfg_in)295 static bool uart_altera_check_configuration(const struct uart_config *cfg_stored,
296 const struct uart_config *cfg_in)
297 {
298 bool ret_val = false;
299
300 if ((cfg_stored->parity == cfg_in->parity)
301 && (cfg_stored->stop_bits == cfg_in->stop_bits)
302 && (cfg_stored->data_bits == cfg_in->data_bits)
303 && (cfg_stored->flow_ctrl == cfg_in->flow_ctrl)) {
304 ret_val = true;
305 }
306
307 return ret_val;
308 }
309
310 /**
311 * @brief Set UART configuration using data from *cfg_in.
312 *
313 * @param dev UART : Device struct
314 * @param cfg_in : The input configuration.
315 *
316 * @return 0 if success, -ENOTSUP, if input from cfg_in is not configurable.
317 * -EINVAL if cfg_in is null pointer
318 */
uart_altera_configure(const struct device * dev,const struct uart_config * cfg_in)319 static int uart_altera_configure(const struct device *dev,
320 const struct uart_config *cfg_in)
321 {
322 const struct uart_altera_device_config *config = dev->config;
323 struct uart_altera_device_data * const data = dev->data;
324 struct uart_config * const cfg_stored = &data->uart_cfg;
325 uint32_t divisor_val;
326 int ret_val;
327
328 /* generate fatal error if CONFIG_ASSERT is enabled. */
329 __ASSERT(cfg_in != NULL, "cfg_in is null pointer!");
330
331 /* Stop, if cfg_in is null pointer */
332 if (cfg_in == NULL) {
333 return -EINVAL;
334 }
335
336 /* check if configuration is supported. */
337 if (uart_altera_check_configuration(cfg_stored, cfg_in)
338 && !(config->flags & ALT_AVALON_UART_FB)) {
339 /* calculate and set baudrate. */
340 divisor_val = (CONFIG_SYS_CLOCK_HW_CYCLES_PER_SEC/cfg_in->baudrate) - 1;
341 sys_write32(divisor_val, config->base + ALTERA_AVALON_UART_DIVISOR_REG_OFFSET);
342
343 /* update stored data. */
344 cfg_stored->baudrate = cfg_in->baudrate;
345 ret_val = 0;
346 } else {
347 /* return not supported */
348 ret_val = -ENOTSUP;
349 }
350
351 return ret_val;
352 }
353
354 /**
355 * @brief Get UART configuration and stores in *cfg_out.
356 *
357 * @param dev UART : Device struct
358 * @param cfg_out : The output configuration.
359 *
360 * @return 0 if success.
361 * -EINVAL if cfg_out is null pointer
362 */
uart_altera_config_get(const struct device * dev,struct uart_config * cfg_out)363 static int uart_altera_config_get(const struct device *dev,
364 struct uart_config *cfg_out)
365 {
366 const struct uart_altera_device_data *data = dev->data;
367
368 /* generate fatal error if CONFIG_ASSERT is enabled. */
369 __ASSERT(cfg_out != NULL, "cfg_out is null pointer!");
370
371 /* Stop, if cfg_out is null pointer */
372 if (cfg_out == NULL) {
373 return -EINVAL;
374 }
375
376 *cfg_out = data->uart_cfg;
377 return 0;
378 }
379 #endif /* CONFIG_UART_USE_RUNTIME_CONFIGURE */
380
381 #ifdef CONFIG_UART_INTERRUPT_DRIVEN
382 /**
383 * @brief Fill FIFO with data
384 * This function is expected to be called from UART interrupt handler (ISR),
385 * if uart_irq_tx_ready() returns true. This function does not block!
386 * IP has no fifo. Hence only 1 data can be sent at a time!
387 *
388 * @param dev UART device struct
389 * @param tx_data Data to transmit
390 * @param size Number of bytes to send (unused)
391 *
392 * @return Number of bytes sent
393 */
uart_altera_fifo_fill(const struct device * dev,const uint8_t * tx_data,int size)394 static int uart_altera_fifo_fill(const struct device *dev,
395 const uint8_t *tx_data,
396 int size)
397 {
398 ARG_UNUSED(size);
399
400 const struct uart_altera_device_config *config = dev->config;
401 struct uart_altera_device_data *data = dev->data;
402 int ret_val;
403
404 /* generate fatal error if CONFIG_ASSERT is enabled. */
405 __ASSERT(tx_data != NULL, "tx_data is null pointer!");
406
407 /* Stop, if tx_data is null pointer */
408 if (tx_data == NULL) {
409 return 0;
410 }
411
412 k_spinlock_key_t key = k_spin_lock(&data->lock);
413
414 if (data->status_act & ALTERA_AVALON_UART_STATUS_TRDY_MSK) {
415 sys_write32(*tx_data, config->base + ALTERA_AVALON_UART_TXDATA_REG_OFFSET);
416 ret_val = 1;
417 /* function may be called in a loop. update the actual status! */
418 data->status_act = sys_read32(config->base + ALTERA_AVALON_UART_STATUS_REG_OFFSET);
419 } else {
420 ret_val = 0;
421 }
422
423 #ifdef CONFIG_UART_ALTERA_LINE_CTRL_WORKAROUND
424 /* clear and CTS rising edge! */
425 data->dcts_rising = 0;
426 #endif /* CONFIG_UART_ALTERA_LINE_CTRL_WORKAROUND */
427
428 k_spin_unlock(&data->lock, key);
429
430 return ret_val;
431 }
432
433 /**
434 * @brief Read data from FIFO
435 * This function is expected to be called from UART interrupt handler (ISR),
436 * if uart_irq_rx_ready() returns true.
437 * IP has no fifo. Hence only 1 data can be read at a time!
438 *
439 * @param dev UART device struct
440 * @param rx_data Data container
441 * @param size Container size
442 *
443 * @return Number of bytes read
444 */
uart_altera_fifo_read(const struct device * dev,uint8_t * rx_data,const int size)445 static int uart_altera_fifo_read(const struct device *dev, uint8_t *rx_data,
446 const int size)
447 {
448 ARG_UNUSED(size);
449
450 const struct uart_altera_device_config *config = dev->config;
451 struct uart_altera_device_data *data = dev->data;
452 int ret_val;
453
454 /* generate fatal error if CONFIG_ASSERT is enabled. */
455 __ASSERT(rx_data != NULL, "rx_data is null pointer!");
456
457 /* Stop, if rx_data is null pointer */
458 if (rx_data == NULL) {
459 return 0;
460 }
461
462 k_spinlock_key_t key = k_spin_lock(&data->lock);
463
464 if (data->status_act & ALTERA_AVALON_UART_STATUS_RRDY_MSK) {
465 *rx_data = sys_read32(config->base + ALTERA_AVALON_UART_RXDATA_REG_OFFSET);
466 ret_val = 1;
467
468 /* function may be called in a loop. update the actual status! */
469 data->status_act = sys_read32(config->base + ALTERA_AVALON_UART_STATUS_REG_OFFSET);
470 } else {
471 ret_val = 0;
472 }
473
474 #ifdef CONFIG_UART_ALTERA_LINE_CTRL_WORKAROUND
475 /* assert RTS as soon as rx data is read, as IP has no fifo. */
476 data->status_act = sys_read32(config->base + ALTERA_AVALON_UART_STATUS_REG_OFFSET);
477 if (((data->status_act & ALTERA_AVALON_UART_STATUS_RRDY_MSK) == 0)
478 && (data->status_act & ALTERA_AVALON_UART_STATUS_CTS_MSK)) {
479 data->control_val |= ALTERA_AVALON_UART_CONTROL_RTS_MSK;
480 sys_write32(data->control_val, config->base
481 + ALTERA_AVALON_UART_CONTROL_REG_OFFSET);
482 }
483 #endif /* CONFIG_UART_ALTERA_LINE_CTRL_WORKAROUND */
484
485 k_spin_unlock(&data->lock, key);
486
487 return ret_val;
488 }
489
490 /**
491 * @brief Enable TX interrupt
492 *
493 * @param dev UART device struct
494 */
uart_altera_irq_tx_enable(const struct device * dev)495 static void uart_altera_irq_tx_enable(const struct device *dev)
496 {
497 struct uart_altera_device_data *data = dev->data;
498 const struct uart_altera_device_config *config = dev->config;
499
500 k_spinlock_key_t key = k_spin_lock(&data->lock);
501
502 data->control_val |= ALTERA_AVALON_UART_CONTROL_TRDY_MSK;
503
504 #ifdef CONFIG_UART_LINE_CTRL
505 /* also enable RTS, if flow control is enabled. */
506 data->control_val |= ALTERA_AVALON_UART_CONTROL_RTS_MSK;
507 #endif
508
509 sys_write32(data->control_val, config->base + ALTERA_AVALON_UART_CONTROL_REG_OFFSET);
510
511 k_spin_unlock(&data->lock, key);
512 }
513
514 /**
515 * @brief Disable TX interrupt
516 *
517 * @param dev UART device struct
518 */
uart_altera_irq_tx_disable(const struct device * dev)519 static void uart_altera_irq_tx_disable(const struct device *dev)
520 {
521 struct uart_altera_device_data *data = dev->data;
522 const struct uart_altera_device_config *config = dev->config;
523
524 k_spinlock_key_t key = k_spin_lock(&data->lock);
525
526 data->control_val &= ~ALTERA_AVALON_UART_CONTROL_TRDY_MSK;
527
528 #ifdef CONFIG_UART_LINE_CTRL
529 /* also disable RTS, if flow control is enabled. */
530 data->control_val &= ~ALTERA_AVALON_UART_CONTROL_RTS_MSK;
531 #endif
532
533 sys_write32(data->control_val, config->base + ALTERA_AVALON_UART_CONTROL_REG_OFFSET);
534
535 k_spin_unlock(&data->lock, key);
536 }
537
538 /**
539 * @brief Check if UART TX buffer can accept a new char.
540 *
541 * @param dev UART device struct
542 *
543 * @return 1 if TX interrupt is enabled and at least one char can be written to UART.
544 * 0 if device is not ready to write a new byte.
545 */
uart_altera_irq_tx_ready(const struct device * dev)546 static int uart_altera_irq_tx_ready(const struct device *dev)
547 {
548 struct uart_altera_device_data *data = dev->data;
549 int ret_val = 0;
550
551 k_spinlock_key_t key = k_spin_lock(&data->lock);
552
553 /* if TX interrupt is enabled */
554 if (data->control_val & ALTERA_AVALON_UART_CONTROL_TRDY_MSK) {
555 /* IP core does not have fifo. Wait until tx data is completely shifted. */
556 if (data->status_act & ALTERA_AVALON_UART_STATUS_TMT_MSK) {
557 ret_val = 1;
558 }
559 }
560
561 #ifdef CONFIG_UART_LINE_CTRL
562 /* if flow control is enabled, set tx not ready, if CTS is low. */
563 if ((data->status_act & ALTERA_AVALON_UART_STATUS_CTS_MSK) == 0) {
564 ret_val = 0;
565 }
566 #ifdef CONFIG_UART_ALTERA_LINE_CTRL_WORKAROUND
567 if (data->dcts_rising == 0) {
568 ret_val = 0;
569 }
570 #endif /* CONFIG_UART_ALTERA_LINE_CTRL_WORKAROUND */
571
572 #endif /* CONFIG_UART_LINE_CTRL */
573
574 k_spin_unlock(&data->lock, key);
575
576 return ret_val;
577 }
578
579 /**
580 * @brief Check if nothing remains to be transmitted
581 *
582 * @param dev UART device struct
583 *
584 * @return 1 if nothing remains to be transmitted, 0 otherwise
585 */
uart_altera_irq_tx_complete(const struct device * dev)586 static int uart_altera_irq_tx_complete(const struct device *dev)
587 {
588 struct uart_altera_device_data *data = dev->data;
589 int ret_val = 0;
590
591 k_spinlock_key_t key = k_spin_lock(&data->lock);
592
593 if (data->status_act & ALTERA_AVALON_UART_STATUS_TMT_MSK) {
594 ret_val = 1;
595 }
596
597 k_spin_unlock(&data->lock, key);
598
599 return ret_val;
600 }
601
602 /**
603 * @brief Enable RX interrupt in
604 *
605 * @param dev UART device struct
606 */
uart_altera_irq_rx_enable(const struct device * dev)607 static void uart_altera_irq_rx_enable(const struct device *dev)
608 {
609 struct uart_altera_device_data *data = dev->data;
610 const struct uart_altera_device_config *config = dev->config;
611
612 k_spinlock_key_t key = k_spin_lock(&data->lock);
613
614 data->control_val |= ALTERA_AVALON_UART_CONTROL_RRDY_MSK;
615 sys_write32(data->control_val, config->base + ALTERA_AVALON_UART_CONTROL_REG_OFFSET);
616
617 k_spin_unlock(&data->lock, key);
618 }
619
620 /**
621 * @brief Disable RX interrupt
622 *
623 * @param dev UART device struct
624 */
uart_altera_irq_rx_disable(const struct device * dev)625 static void uart_altera_irq_rx_disable(const struct device *dev)
626 {
627 struct uart_altera_device_data *data = dev->data;
628 const struct uart_altera_device_config *config = dev->config;
629
630 k_spinlock_key_t key = k_spin_lock(&data->lock);
631
632 data->control_val &= ~ALTERA_AVALON_UART_CONTROL_RRDY_MSK;
633 sys_write32(data->control_val, config->base + ALTERA_AVALON_UART_CONTROL_REG_OFFSET);
634
635 k_spin_unlock(&data->lock, key);
636 }
637
638 /**
639 * @brief Check if Rx IRQ has been raised
640 *
641 * @param dev UART device struct
642 *
643 * @return 1 if an IRQ is ready, 0 otherwise
644 */
uart_altera_irq_rx_ready(const struct device * dev)645 static int uart_altera_irq_rx_ready(const struct device *dev)
646 {
647 struct uart_altera_device_data *data = dev->data;
648 int ret_val = 0;
649
650 k_spinlock_key_t key = k_spin_lock(&data->lock);
651
652 /* if RX interrupt is enabled */
653 if (data->control_val & ALTERA_AVALON_UART_CONTROL_RRDY_MSK) {
654 /* check for space in rx data register */
655 if (data->status_act & ALTERA_AVALON_UART_STATUS_RRDY_MSK) {
656 ret_val = 1;
657 }
658 }
659
660 k_spin_unlock(&data->lock, key);
661
662 return ret_val;
663 }
664
665 /**
666 * @brief This function will cache the status register.
667 *
668 * @param dev UART device struct
669 *
670 * @return 1 for success.
671 */
uart_altera_irq_update(const struct device * dev)672 static int uart_altera_irq_update(const struct device *dev)
673 {
674 struct uart_altera_device_data *data = dev->data;
675 const struct uart_altera_device_config *config = dev->config;
676
677 k_spinlock_key_t key = k_spin_lock(&data->lock);
678
679 data->status_act = sys_read32(config->base + ALTERA_AVALON_UART_STATUS_REG_OFFSET);
680
681 k_spin_unlock(&data->lock, key);
682
683 return 1;
684 }
685
686 /**
687 * @brief Check if any IRQ is pending
688 *
689 * @param dev UART device struct
690 *
691 * @return 1 if an IRQ is pending, 0 otherwise
692 */
uart_altera_irq_is_pending(const struct device * dev)693 static int uart_altera_irq_is_pending(const struct device *dev)
694 {
695 struct uart_altera_device_data *data = dev->data;
696 int ret_val = 0;
697
698 k_spinlock_key_t key = k_spin_lock(&data->lock);
699
700 if (data->status_act & data->control_val & ALTERA_AVALON_UART_PENDING_MASK) {
701 ret_val = 1;
702 }
703
704 k_spin_unlock(&data->lock, key);
705
706 return ret_val;
707 }
708
709 /**
710 * @brief Set the callback function pointer for IRQ.
711 *
712 * @param dev UART device struct
713 * @param cb Callback function pointer.
714 * @param cb_data Data to pass to callback function.
715 */
uart_altera_irq_callback_set(const struct device * dev,uart_irq_callback_user_data_t cb,void * cb_data)716 static void uart_altera_irq_callback_set(const struct device *dev,
717 uart_irq_callback_user_data_t cb,
718 void *cb_data)
719 {
720 struct uart_altera_device_data *data = dev->data;
721
722 /* generate fatal error if CONFIG_ASSERT is enabled. */
723 __ASSERT(cb != NULL, "uart_irq_callback_user_data_t cb is null pointer!");
724
725 k_spinlock_key_t key = k_spin_lock(&data->lock);
726
727 #ifdef CONFIG_UART_ALTERA_EOP
728 if (data->set_eop_cb) {
729 data->cb_eop = cb;
730 data->cb_data_eop = cb_data;
731 data->set_eop_cb = 0;
732 } else {
733 data->cb = cb;
734 data->cb_data = cb_data;
735 }
736 #else
737 data->cb = cb;
738 data->cb_data = cb_data;
739 #endif /* CONFIG_UART_ALTERA_EOP */
740
741 k_spin_unlock(&data->lock, key);
742 }
743
744 #ifdef CONFIG_UART_LINE_CTRL
745 /**
746 * @brief DCTS Interrupt service routine.
747 *
748 * Handles assertion and deassettion of CTS/RTS stignal
749 *
750 * @param dev Pointer to UART device struct
751 */
uart_altera_dcts_isr(const struct device * dev)752 static void uart_altera_dcts_isr(const struct device *dev)
753 {
754 struct uart_altera_device_data *data = dev->data;
755 const struct uart_altera_device_config *config = dev->config;
756
757 k_spinlock_key_t key = k_spin_lock(&data->lock);
758
759 /* Assume that user follows zephyr requirement and update status in their call back. */
760 if (data->status_act & ALTERA_AVALON_UART_STATUS_CTS_MSK) {
761 #ifdef CONFIG_UART_ALTERA_LINE_CTRL_WORKAROUND
762 data->dcts_rising = 1;
763 #endif /* CONFIG_UART_ALTERA_LINE_CTRL_WORKAROUND */
764
765 /* check if device is ready to receive character */
766 if ((data->status_act & ALTERA_AVALON_UART_STATUS_RRDY_MSK) == 0) {
767 /* Assert RTS to inform other UART. */
768 data->control_val |= ALTERA_AVALON_UART_CONTROL_RTS_MSK;
769 sys_write32(data->control_val, config->base
770 + ALTERA_AVALON_UART_CONTROL_REG_OFFSET);
771 }
772 } else {
773 /* other UART deasserts RTS */
774 if (data->status_act & ALTERA_AVALON_UART_STATUS_TMT_MSK) {
775 /* only deasserts if not transmitting. */
776 data->control_val &= ~ALTERA_AVALON_UART_CONTROL_RTS_MSK;
777 sys_write32(data->control_val, config->base
778 + ALTERA_AVALON_UART_CONTROL_REG_OFFSET);
779 }
780 }
781
782 k_spin_unlock(&data->lock, key);
783 }
784 #endif /* CONFIG_UART_LINE_CTRL */
785
786 /**
787 * @brief Interrupt service routine.
788 *
789 * This simply calls the callback function, if one exists.
790 *
791 * @param dev Pointer to UART device struct
792 *
793 */
uart_altera_isr(const struct device * dev)794 static void uart_altera_isr(const struct device *dev)
795 {
796 struct uart_altera_device_data *data = dev->data;
797 const struct uart_altera_device_config *config = dev->config;
798
799 uart_irq_callback_user_data_t callback = data->cb;
800
801 /* Pre ISR */
802 #ifdef CONFIG_UART_ALTERA_LINE_CTRL_WORKAROUND
803 /* deassert RTS as soon as rx data is received, as IP has no fifo. */
804 data->status_act = sys_read32(config->base + ALTERA_AVALON_UART_STATUS_REG_OFFSET);
805 if (data->status_act & ALTERA_AVALON_UART_STATUS_RRDY_MSK) {
806 data->control_val &= ~ALTERA_AVALON_UART_CONTROL_RTS_MSK;
807 sys_write32(data->control_val, config->base
808 + ALTERA_AVALON_UART_CONTROL_REG_OFFSET);
809 }
810 #endif /* CONFIG_UART_ALTERA_LINE_CTRL_WORKAROUND */
811
812 if (callback) {
813 callback(dev, data->cb_data);
814 }
815
816 /* Post ISR */
817 #if CONFIG_UART_ALTERA_EOP
818 data->status_act = sys_read32(config->base + ALTERA_AVALON_UART_STATUS_REG_OFFSET);
819
820 if (data->status_act & ALTERA_AVALON_UART_STATUS_EOP_MSK) {
821 callback = data->cb_eop;
822 if (callback) {
823 callback(dev, data->cb_data_eop);
824 }
825 }
826 #endif /* CONFIG_UART_ALTERA_EOP */
827
828 #ifdef CONFIG_UART_LINE_CTRL
829 /* handles RTS/CTS signal */
830 if (data->status_act & ALTERA_AVALON_UART_STATUS_DCTS_MSK) {
831 uart_altera_dcts_isr(dev);
832 }
833 #endif
834
835 /* clear status after all interrupts are handled. */
836 sys_write32(ALTERA_AVALON_UART_CLEAR_STATUS_VAL, config->base
837 + ALTERA_AVALON_UART_STATUS_REG_OFFSET);
838 }
839
840 #ifdef CONFIG_UART_DRV_CMD
841 /**
842 * @brief Send extra command to driver
843 *
844 * @param dev UART device struct
845 * @param cmd Command to driver
846 * @param p Parameter to the command
847 *
848 * @return 0 if successful, failed otherwise
849 */
uart_altera_drv_cmd(const struct device * dev,uint32_t cmd,uint32_t p)850 static int uart_altera_drv_cmd(const struct device *dev, uint32_t cmd,
851 uint32_t p)
852 {
853 struct uart_altera_device_data *data = dev->data;
854 #if CONFIG_UART_ALTERA_EOP
855 const struct uart_altera_device_config *config = dev->config;
856 #endif
857 int ret_val = -ENOTSUP;
858 k_spinlock_key_t key = k_spin_lock(&data->lock);
859
860 switch (cmd) {
861 #if CONFIG_UART_ALTERA_EOP
862 case CMD_ENABLE_EOP:
863 /* enable EOP interrupt */
864 data->control_val |= ALTERA_AVALON_UART_CONTROL_EOP_MSK;
865 sys_write32(data->control_val, config->base
866 + ALTERA_AVALON_UART_CONTROL_REG_OFFSET);
867
868 /* set EOP character */
869 sys_write32((uint8_t) p, config->base + ALTERA_AVALON_UART_EOP_REG_OFFSET);
870
871 /* after this, user needs to call uart_irq_callback_set
872 * to set data->cb_eop and data->cb_data_eop!
873 */
874 data->set_eop_cb = 1;
875 ret_val = 0;
876 break;
877
878 case CMD_DISABLE_EOP:
879 /* Disable EOP interrupt */
880 data->control_val &= ~ALTERA_AVALON_UART_CONTROL_EOP_MSK;
881 sys_write32(data->control_val, config->base
882 + ALTERA_AVALON_UART_CONTROL_REG_OFFSET);
883
884 /* clear call back */
885 data->cb_eop = NULL;
886 data->cb_data_eop = NULL;
887 ret_val = 0;
888 break;
889 #endif /* CONFIG_UART_ALTERA_EOP */
890 default:
891 ret_val = -ENOTSUP;
892 break;
893 };
894
895 k_spin_unlock(&data->lock, key);
896
897 return ret_val;
898 }
899
900 #endif /* CONFIG_UART_DRV_CMD */
901
902 #endif /* CONFIG_UART_INTERRUPT_DRIVEN */
903
904 static const struct uart_driver_api uart_altera_driver_api = {
905 .poll_in = uart_altera_poll_in,
906 .poll_out = uart_altera_poll_out,
907 .err_check = uart_altera_err_check,
908 #ifdef CONFIG_UART_USE_RUNTIME_CONFIGURE
909 .configure = uart_altera_configure,
910 .config_get = uart_altera_config_get,
911 #endif /* CONFIG_UART_USE_RUNTIME_CONFIGURE */
912
913 #ifdef CONFIG_UART_INTERRUPT_DRIVEN
914 .fifo_fill = uart_altera_fifo_fill,
915 .fifo_read = uart_altera_fifo_read,
916 .irq_tx_enable = uart_altera_irq_tx_enable,
917 .irq_tx_disable = uart_altera_irq_tx_disable,
918 .irq_tx_ready = uart_altera_irq_tx_ready,
919 .irq_tx_complete = uart_altera_irq_tx_complete,
920 .irq_rx_enable = uart_altera_irq_rx_enable,
921 .irq_rx_disable = uart_altera_irq_rx_disable,
922 .irq_rx_ready = uart_altera_irq_rx_ready,
923 .irq_is_pending = uart_altera_irq_is_pending,
924 .irq_update = uart_altera_irq_update,
925 .irq_callback_set = uart_altera_irq_callback_set,
926 #endif
927
928 #ifdef CONFIG_UART_DRV_CMD
929 .drv_cmd = uart_altera_drv_cmd,
930 #endif
931 };
932
933 #ifdef CONFIG_UART_INTERRUPT_DRIVEN
934
935 #define UART_ALTERA_IRQ_CONFIG_FUNC(n) \
936 static void uart_altera_irq_config_func_##n(const struct device *dev) \
937 { \
938 IRQ_CONNECT(DT_INST_IRQN(n), \
939 DT_INST_IRQ(n, priority), \
940 uart_altera_isr, \
941 DEVICE_DT_INST_GET(n), 0); \
942 \
943 irq_enable(DT_INST_IRQN(n)); \
944 }
945
946 #define UART_ALTERA_IRQ_CONFIG_INIT(n) \
947 .irq_config_func = uart_altera_irq_config_func_##n, \
948 .irq_num = DT_INST_IRQN(n),
949
950 #else
951
952 #define UART_ALTERA_IRQ_CONFIG_FUNC(n)
953 #define UART_ALTERA_IRQ_CONFIG_INIT(n)
954
955 #endif /* CONFIG_UART_INTERRUPT_DRIVEN */
956
957 #define UART_ALTERA_DEVICE_INIT(n) \
958 UART_ALTERA_IRQ_CONFIG_FUNC(n) \
959 static struct uart_altera_device_data uart_altera_dev_data_##n = { \
960 .uart_cfg = \
961 { \
962 .baudrate = DT_INST_PROP(n, current_speed), \
963 .parity = DT_INST_ENUM_IDX_OR(n, parity, \
964 UART_CFG_PARITY_NONE), \
965 .stop_bits = DT_INST_ENUM_IDX_OR(n, stop_bits, \
966 UART_CFG_STOP_BITS_1), \
967 .data_bits = DT_INST_ENUM_IDX_OR(n, data_bits, \
968 UART_CFG_DATA_BITS_8), \
969 .flow_ctrl = DT_INST_PROP(n, hw_flow_control) ? \
970 UART_CFG_FLOW_CTRL_RTS_CTS : \
971 UART_CFG_FLOW_CTRL_NONE, \
972 }, \
973 }; \
974 \
975 static const struct uart_altera_device_config uart_altera_dev_cfg_##n = { \
976 .base = DT_INST_REG_ADDR(n), \
977 .flags = ((DT_INST_PROP(n, fixed_baudrate)?ALT_AVALON_UART_FB:0) \
978 |(DT_INST_PROP(n, hw_flow_control)?ALT_AVALON_UART_FC:0)), \
979 UART_ALTERA_IRQ_CONFIG_INIT(n) \
980 }; \
981 \
982 DEVICE_DT_INST_DEFINE(n, \
983 uart_altera_init, \
984 NULL, \
985 &uart_altera_dev_data_##n, \
986 &uart_altera_dev_cfg_##n, \
987 PRE_KERNEL_1, \
988 CONFIG_SERIAL_INIT_PRIORITY, \
989 &uart_altera_driver_api);
990
991 DT_INST_FOREACH_STATUS_OKAY(UART_ALTERA_DEVICE_INIT)
992