Branch data Line data Source code
1 : : /*
2 : : * Copyright (c) 2020 Henrik Brix Andersen <henrik@brixandersen.dk>
3 : : *
4 : : * Based on uart_mcux_lpuart.c, which is:
5 : : * Copyright (c) 2017, NXP
6 : : *
7 : : * SPDX-License-Identifier: Apache-2.0
8 : : */
9 : :
10 : : #define DT_DRV_COMPAT xlnx_xps_uartlite_1_00_a
11 : :
12 : : #include <zephyr/device.h>
13 : : #include <zephyr/drivers/uart.h>
14 : : #include <zephyr/irq.h>
15 : : #include <zephyr/kernel.h>
16 : : #include <zephyr/sys/sys_io.h>
17 : :
18 : : /* AXI UART Lite v2 registers offsets (See Xilinx PG142 for details) */
19 : : #define RX_FIFO_OFFSET 0x00
20 : : #define TX_FIFO_OFFSET 0x04
21 : : #define STAT_REG_OFFSET 0x08
22 : : #define CTRL_REG_OFFSET 0x0c
23 : :
24 : : /* STAT_REG bit definitions */
25 : : #define STAT_REG_RX_FIFO_VALID_DATA BIT(0)
26 : : #define STAT_REG_RX_FIFO_FULL BIT(1)
27 : : #define STAT_REG_TX_FIFO_EMPTY BIT(2)
28 : : #define STAT_REG_TX_FIFO_FULL BIT(3)
29 : : #define STAT_REG_INTR_ENABLED BIT(4)
30 : : #define STAT_REG_OVERRUN_ERROR BIT(5)
31 : : #define STAT_REG_FRAME_ERROR BIT(6)
32 : : #define STAT_REG_PARITY_ERROR BIT(7)
33 : :
34 : : /* STAT_REG bit masks */
35 : : #define STAT_REG_ERROR_MASK GENMASK(7, 5)
36 : :
37 : : /* CTRL_REG bit definitions */
38 : : #define CTRL_REG_RST_TX_FIFO BIT(0)
39 : : #define CTRL_REG_RST_RX_FIFO BIT(1)
40 : : #define CTRL_REG_ENABLE_INTR BIT(4)
41 : :
42 : : struct xlnx_uartlite_config {
43 : : mm_reg_t base;
44 : : #ifdef CONFIG_UART_INTERRUPT_DRIVEN
45 : : void (*irq_config_func)(const struct device *dev);
46 : : #endif /* CONFIG_UART_INTERRUPT_DRIVEN */
47 : : };
48 : :
49 : : struct xlnx_uartlite_data {
50 : : uint32_t errors;
51 : :
52 : : /* spinlocks for RX and TX FIFO preventing a bus error */
53 : : struct k_spinlock rx_lock;
54 : : struct k_spinlock tx_lock;
55 : :
56 : : #ifdef CONFIG_UART_INTERRUPT_DRIVEN
57 : : const struct device *dev;
58 : : struct k_timer timer;
59 : : uart_irq_callback_user_data_t callback;
60 : : void *callback_data;
61 : :
62 : : volatile uint8_t tx_irq_enabled : 1;
63 : : volatile uint8_t rx_irq_enabled : 1;
64 : : #endif /* CONFIG_UART_INTERRUPT_DRIVEN */
65 : : };
66 : :
67 : 362108 : static inline uint32_t xlnx_uartlite_read_status(const struct device *dev)
68 : : {
69 : 362108 : const struct xlnx_uartlite_config *config = dev->config;
70 : 362108 : struct xlnx_uartlite_data *data = dev->data;
71 : : uint32_t status;
72 : :
73 : : /* Cache errors as they are cleared by reading the STAT_REG */
74 : 362108 : status = sys_read32(config->base + STAT_REG_OFFSET);
75 : 362108 : data->errors &= (status & STAT_REG_ERROR_MASK);
76 : :
77 : : /* Return current status and previously cached errors */
78 : 362108 : return status | data->errors;
79 : : }
80 : :
81 : 0 : static inline void xlnx_uartlite_clear_status(const struct device *dev)
82 : : {
83 : 0 : struct xlnx_uartlite_data *data = dev->data;
84 : :
85 : : /* Clear cached errors */
86 : 0 : data->errors = 0;
87 : 0 : }
88 : :
89 : 10 : static inline unsigned char xlnx_uartlite_read_rx_fifo(const struct device *dev)
90 : : {
91 : 10 : const struct xlnx_uartlite_config *config = dev->config;
92 : :
93 : 10 : return (sys_read32(config->base + RX_FIFO_OFFSET) & BIT_MASK(8));
94 : : }
95 : :
96 : 56913 : static inline void xlnx_uartlite_write_tx_fifo(const struct device *dev,
97 : : unsigned char c)
98 : : {
99 : 56913 : const struct xlnx_uartlite_config *config = dev->config;
100 : :
101 : 56913 : sys_write32((uint32_t)c, config->base + TX_FIFO_OFFSET);
102 : 56913 : }
103 : :
104 : 14033 : static int xlnx_uartlite_poll_in(const struct device *dev, unsigned char *c)
105 : : {
106 : : uint32_t status;
107 : : k_spinlock_key_t key;
108 : 14033 : struct xlnx_uartlite_data *data = dev->data;
109 : 14033 : int ret = -1;
110 : :
111 : 14033 : key = k_spin_lock(&data->rx_lock);
112 : 14033 : status = xlnx_uartlite_read_status(dev);
113 [ + + ]: 14033 : if ((status & STAT_REG_RX_FIFO_VALID_DATA) != 0) {
114 : 6 : *c = xlnx_uartlite_read_rx_fifo(dev);
115 : 6 : ret = 0;
116 : : }
117 : 14033 : k_spin_unlock(&data->rx_lock, key);
118 : :
119 : 14033 : return ret;
120 : : }
121 : :
122 : 56891 : static void xlnx_uartlite_poll_out(const struct device *dev, unsigned char c)
123 : : {
124 : : uint32_t status;
125 : : k_spinlock_key_t key;
126 : 56891 : struct xlnx_uartlite_data *data = dev->data;
127 : 56891 : bool done = false;
128 : :
129 [ + + ]: 404878 : while (!done) {
130 : 347987 : key = k_spin_lock(&data->tx_lock);
131 : 347987 : status = xlnx_uartlite_read_status(dev);
132 [ + + ]: 347987 : if ((status & STAT_REG_TX_FIFO_FULL) == 0) {
133 : 56891 : xlnx_uartlite_write_tx_fifo(dev, c);
134 : 56891 : done = true;
135 : : }
136 : 347987 : k_spin_unlock(&data->tx_lock, key);
137 : : }
138 : 56891 : }
139 : :
140 : 0 : static int xlnx_uartlite_err_check(const struct device *dev)
141 : : {
142 : 0 : uint32_t status = xlnx_uartlite_read_status(dev);
143 : 0 : int err = 0;
144 : :
145 [ # # ]: 0 : if (status & STAT_REG_OVERRUN_ERROR) {
146 : 0 : err |= UART_ERROR_OVERRUN;
147 : : }
148 : :
149 [ # # ]: 0 : if (status & STAT_REG_PARITY_ERROR) {
150 : 0 : err |= UART_ERROR_PARITY;
151 : : }
152 : :
153 [ # # ]: 0 : if (status & STAT_REG_FRAME_ERROR) {
154 : 0 : err |= UART_ERROR_FRAMING;
155 : : }
156 : :
157 : 0 : xlnx_uartlite_clear_status(dev);
158 : :
159 : 0 : return err;
160 : : }
161 : :
162 : : #ifdef CONFIG_UART_INTERRUPT_DRIVEN
163 : 3 : static inline void xlnx_uartlite_irq_enable(const struct device *dev)
164 : : {
165 : 3 : const struct xlnx_uartlite_config *config = dev->config;
166 : :
167 : 3 : sys_write32(CTRL_REG_ENABLE_INTR, config->base + CTRL_REG_OFFSET);
168 : 3 : }
169 : :
170 : 4 : static inline void xlnx_uartlite_irq_cond_disable(const struct device *dev)
171 : : {
172 : 4 : const struct xlnx_uartlite_config *config = dev->config;
173 : 4 : struct xlnx_uartlite_data *data = dev->data;
174 : :
175 : : /* TX and RX IRQs are shared. Only disable if both are disabled. */
176 [ + - + - ]: 4 : if (!data->tx_irq_enabled && !data->rx_irq_enabled) {
177 : 4 : sys_write32(0, config->base + CTRL_REG_OFFSET);
178 : : }
179 : 4 : }
180 : :
181 : 1 : static int xlnx_uartlite_fifo_fill(const struct device *dev,
182 : : const uint8_t *tx_data,
183 : : int len)
184 : : {
185 : : uint32_t status;
186 : : k_spinlock_key_t key;
187 : 1 : struct xlnx_uartlite_data *data = dev->data;
188 : 1 : int count = 0U;
189 : :
190 [ + + ]: 54 : while (len - count > 0) {
191 : 53 : key = k_spin_lock(&data->tx_lock);
192 : 53 : status = xlnx_uartlite_read_status(dev);
193 [ + + ]: 53 : if ((status & STAT_REG_TX_FIFO_FULL) == 0U) {
194 : 22 : xlnx_uartlite_write_tx_fifo(dev, tx_data[count++]);
195 : : }
196 : 53 : k_spin_unlock(&data->tx_lock, key);
197 : : }
198 : :
199 : 1 : return count;
200 : : }
201 : :
202 : 4 : static int xlnx_uartlite_fifo_read(const struct device *dev, uint8_t *rx_data,
203 : : const int len)
204 : : {
205 : : uint32_t status;
206 : : k_spinlock_key_t key;
207 : 4 : struct xlnx_uartlite_data *data = dev->data;
208 : 4 : int count = 0U;
209 : :
210 [ + + ]: 8 : while ((len - count) > 0) {
211 : 4 : key = k_spin_lock(&data->rx_lock);
212 : 4 : status = xlnx_uartlite_read_status(dev);
213 [ + - ]: 4 : if ((status & STAT_REG_RX_FIFO_VALID_DATA) != 0) {
214 : 4 : rx_data[count++] = xlnx_uartlite_read_rx_fifo(dev);
215 : : }
216 : 4 : k_spin_unlock(&data->rx_lock, key);
217 [ - + ]: 4 : if (!(status & STAT_REG_RX_FIFO_VALID_DATA)) {
218 : 0 : break;
219 : : }
220 : : }
221 : :
222 : 4 : return count;
223 : : }
224 : :
225 : 0 : static void xlnx_uartlite_tx_soft_isr(struct k_timer *timer)
226 : : {
227 : 0 : struct xlnx_uartlite_data *data =
228 : : CONTAINER_OF(timer, struct xlnx_uartlite_data, timer);
229 : :
230 [ # # ]: 0 : if (data->callback) {
231 : 0 : data->callback(data->dev, data->callback_data);
232 : : }
233 : 0 : }
234 : :
235 : 1 : static void xlnx_uartlite_irq_tx_enable(const struct device *dev)
236 : : {
237 : 1 : struct xlnx_uartlite_data *data = dev->data;
238 : : uint32_t status;
239 : :
240 : 1 : data->tx_irq_enabled = true;
241 : 1 : status = xlnx_uartlite_read_status(dev);
242 : 1 : xlnx_uartlite_irq_enable(dev);
243 : :
244 [ - + - - ]: 1 : if ((status & STAT_REG_TX_FIFO_EMPTY) && data->callback) {
245 : : /*
246 : : * TX_FIFO_EMPTY event already generated an edge
247 : : * interrupt. Generate a soft interrupt and have it call the
248 : : * callback function in timer isr context.
249 : : */
250 : 0 : k_timer_start(&data->timer, K_NO_WAIT, K_NO_WAIT);
251 : : }
252 : 1 : }
253 : :
254 : 3 : static void xlnx_uartlite_irq_tx_disable(const struct device *dev)
255 : : {
256 : 3 : struct xlnx_uartlite_data *data = dev->data;
257 : :
258 : 3 : data->tx_irq_enabled = false;
259 : 3 : xlnx_uartlite_irq_cond_disable(dev);
260 : 3 : }
261 : :
262 : 15 : static int xlnx_uartlite_irq_tx_ready(const struct device *dev)
263 : : {
264 : 15 : struct xlnx_uartlite_data *data = dev->data;
265 : 15 : uint32_t status = xlnx_uartlite_read_status(dev);
266 : :
267 [ + - ]: 30 : return (((status & STAT_REG_TX_FIFO_FULL) == 0U) &&
268 [ + + ]: 15 : data->tx_irq_enabled);
269 : : }
270 : :
271 : 0 : static int xlnx_uartlite_irq_tx_complete(const struct device *dev)
272 : : {
273 : 0 : uint32_t status = xlnx_uartlite_read_status(dev);
274 : :
275 : 0 : return (status & STAT_REG_TX_FIFO_EMPTY);
276 : : }
277 : :
278 : 2 : static void xlnx_uartlite_irq_rx_enable(const struct device *dev)
279 : : {
280 : 2 : struct xlnx_uartlite_data *data = dev->data;
281 : :
282 : 2 : data->rx_irq_enabled = true;
283 : : /* RX_FIFO_VALID_DATA generates a level interrupt */
284 : 2 : xlnx_uartlite_irq_enable(dev);
285 : 2 : }
286 : :
287 : 1 : static void xlnx_uartlite_irq_rx_disable(const struct device *dev)
288 : : {
289 : 1 : struct xlnx_uartlite_data *data = dev->data;
290 : :
291 : 1 : data->rx_irq_enabled = false;
292 : 1 : xlnx_uartlite_irq_cond_disable(dev);
293 : 1 : }
294 : :
295 : 15 : static int xlnx_uartlite_irq_rx_ready(const struct device *dev)
296 : : {
297 : 15 : struct xlnx_uartlite_data *data = dev->data;
298 : 15 : uint32_t status = xlnx_uartlite_read_status(dev);
299 : :
300 [ + + ]: 19 : return ((status & STAT_REG_RX_FIFO_VALID_DATA) &&
301 [ + - ]: 4 : data->rx_irq_enabled);
302 : : }
303 : :
304 : 6 : static int xlnx_uartlite_irq_is_pending(const struct device *dev)
305 : : {
306 [ + - - + ]: 12 : return (xlnx_uartlite_irq_tx_ready(dev) ||
307 : 6 : xlnx_uartlite_irq_rx_ready(dev));
308 : : }
309 : :
310 : 15 : static int xlnx_uartlite_irq_update(const struct device *dev)
311 : : {
312 : 15 : return 1;
313 : : }
314 : :
315 : 3 : static void xlnx_uartlite_irq_callback_set(const struct device *dev,
316 : : uart_irq_callback_user_data_t cb,
317 : : void *user_data)
318 : : {
319 : 3 : struct xlnx_uartlite_data *data = dev->data;
320 : :
321 : 3 : data->callback = cb;
322 : 3 : data->callback_data = user_data;
323 : 3 : }
324 : :
325 : 15 : static __unused void xlnx_uartlite_isr(const struct device *dev)
326 : : {
327 : 15 : struct xlnx_uartlite_data *data = dev->data;
328 : :
329 [ + - ]: 15 : if (data->callback) {
330 : 15 : data->callback(dev, data->callback_data);
331 : : }
332 : 15 : }
333 : :
334 : : #endif /* CONFIG_UART_INTERRUPT_DRIVEN */
335 : :
336 : 1 : static int xlnx_uartlite_init(const struct device *dev)
337 : : {
338 : 1 : const struct xlnx_uartlite_config *config = dev->config;
339 : : #ifdef CONFIG_UART_INTERRUPT_DRIVEN
340 : 1 : struct xlnx_uartlite_data *data = dev->data;
341 : :
342 : 1 : data->dev = dev;
343 : 1 : k_timer_init(&data->timer, &xlnx_uartlite_tx_soft_isr, NULL);
344 : : #endif /* CONFIG_UART_INTERRUPT_DRIVEN */
345 : :
346 : : /* Reset FIFOs and disable interrupts */
347 : 1 : sys_write32(CTRL_REG_RST_RX_FIFO | CTRL_REG_RST_TX_FIFO,
348 : 1 : config->base + CTRL_REG_OFFSET);
349 : :
350 : : #ifdef CONFIG_UART_INTERRUPT_DRIVEN
351 : 1 : config->irq_config_func(dev);
352 : : #endif /* CONFIG_UART_INTERRUPT_DRIVEN */
353 : :
354 : 1 : return 0;
355 : : }
356 : :
357 : : static const struct uart_driver_api xlnx_uartlite_driver_api = {
358 : : .poll_in = xlnx_uartlite_poll_in,
359 : : .poll_out = xlnx_uartlite_poll_out,
360 : : .err_check = xlnx_uartlite_err_check,
361 : : #ifdef CONFIG_UART_INTERRUPT_DRIVEN
362 : : .fifo_fill = xlnx_uartlite_fifo_fill,
363 : : .fifo_read = xlnx_uartlite_fifo_read,
364 : : .irq_tx_enable = xlnx_uartlite_irq_tx_enable,
365 : : .irq_tx_disable = xlnx_uartlite_irq_tx_disable,
366 : : .irq_tx_ready = xlnx_uartlite_irq_tx_ready,
367 : : .irq_tx_complete = xlnx_uartlite_irq_tx_complete,
368 : : .irq_rx_enable = xlnx_uartlite_irq_rx_enable,
369 : : .irq_rx_disable = xlnx_uartlite_irq_rx_disable,
370 : : .irq_rx_ready = xlnx_uartlite_irq_rx_ready,
371 : : .irq_is_pending = xlnx_uartlite_irq_is_pending,
372 : : .irq_update = xlnx_uartlite_irq_update,
373 : : .irq_callback_set = xlnx_uartlite_irq_callback_set,
374 : : #endif /* CONFIG_UART_INTERRUPT_DRIVEN */
375 : : };
376 : :
377 : : #ifdef CONFIG_UART_INTERRUPT_DRIVEN
378 : : #define XLNX_UARTLITE_IRQ_INIT(n, i) \
379 : : do { \
380 : : IRQ_CONNECT(DT_INST_IRQN_BY_IDX(n, i), \
381 : : DT_INST_IRQ_BY_IDX(n, i, priority), \
382 : : xlnx_uartlite_isr, \
383 : : DEVICE_DT_INST_GET(n), 0); \
384 : : \
385 : : irq_enable(DT_INST_IRQN_BY_IDX(n, i)); \
386 : : } while (false)
387 : : #define XLNX_UARTLITE_CONFIG_FUNC(n) \
388 : : static void xlnx_uartlite_config_func_##n(const struct device *dev) \
389 : : { \
390 : : /* IRQ line not always present on all instances */ \
391 : : IF_ENABLED(DT_INST_IRQ_HAS_IDX(n, 0), \
392 : : (XLNX_UARTLITE_IRQ_INIT(n, 0);)) \
393 : : }
394 : : #define XLNX_UARTLITE_IRQ_CFG_FUNC_INIT(n) \
395 : : .irq_config_func = xlnx_uartlite_config_func_##n
396 : : #define XLNX_UARTLITE_INIT_CFG(n) \
397 : : XLNX_UARTLITE_DECLARE_CFG(n, XLNX_UARTLITE_IRQ_CFG_FUNC_INIT(n))
398 : : #else
399 : : #define XLNX_UARTLITE_CONFIG_FUNC(n)
400 : : #define XLNX_UARTLITE_IRQ_CFG_FUNC_INIT
401 : : #define XLNX_UARTLITE_INIT_CFG(n) \
402 : : XLNX_UARTLITE_DECLARE_CFG(n, XLNX_UARTLITE_IRQ_CFG_FUNC_INIT)
403 : : #endif
404 : :
405 : : #define XLNX_UARTLITE_DECLARE_CFG(n, IRQ_FUNC_INIT) \
406 : : static const struct xlnx_uartlite_config xlnx_uartlite_##n##_config = { \
407 : : .base = DT_INST_REG_ADDR(n), \
408 : : IRQ_FUNC_INIT \
409 : : }
410 : :
411 : : #define XLNX_UARTLITE_INIT(n) \
412 : : static struct xlnx_uartlite_data xlnx_uartlite_##n##_data; \
413 : : \
414 : : static const struct xlnx_uartlite_config xlnx_uartlite_##n##_config;\
415 : : \
416 : : DEVICE_DT_INST_DEFINE(n, \
417 : : &xlnx_uartlite_init, \
418 : : NULL, \
419 : : &xlnx_uartlite_##n##_data, \
420 : : &xlnx_uartlite_##n##_config, \
421 : : PRE_KERNEL_1, \
422 : : CONFIG_SERIAL_INIT_PRIORITY, \
423 : : &xlnx_uartlite_driver_api); \
424 : : \
425 : : XLNX_UARTLITE_CONFIG_FUNC(n) \
426 : : \
427 : : XLNX_UARTLITE_INIT_CFG(n);
428 : :
429 : 1 : DT_INST_FOREACH_STATUS_OKAY(XLNX_UARTLITE_INIT)
|