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 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