1 /*
2 * Copyright (c) 2018 Antmicro <www.antmicro.com>
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 #define DT_DRV_COMPAT microchip_coreuart
8
9 #include <zephyr/kernel.h>
10 #include <zephyr/arch/cpu.h>
11 #include <zephyr/drivers/uart.h>
12
13
14 /* UART REGISTERS DEFINITIONS */
15
16 /* TX register */
17 #define TXDATA_REG_OFFSET 0x0
18
19 #define TXDATA_OFFSET 0x0
20 #define TXDATA_MASK 0xFF
21 #define TXDATA_SHIFT 0
22
23 /* RX register */
24 #define RXDATA_REG_OFFSET 0x4
25
26 #define RXDATA_OFFSET 0x4
27 #define RXDATA_MASK 0xFF
28 #define RXDATA_SHIFT 0
29
30 /* Control1 register */
31 #define CTRL1_REG_OFFSET 0x8
32
33 /* Baud value lower 8 bits */
34 #define CTRL1_BAUDVALUE_OFFSET 0x8
35 #define CTRL1_BAUDVALUE_MASK 0xFF
36 #define CTRL1_BAUDVALUE_SHIFT 0
37
38 /* Control2 register */
39 #define CTRL2_REG_OFFSET 0xC
40
41 /* Bit length */
42 #define CTRL2_BIT_LENGTH_OFFSET 0xC
43 #define CTRL2_BIT_LENGTH_MASK 0x01
44 #define CTRL2_BIT_LENGTH_SHIFT 0
45
46 /* Parity enable */
47 #define CTRL2_PARITY_EN_OFFSET 0xC
48 #define CTRL2_PARITY_EN_MASK 0x02
49 #define CTRL2_PARITY_EN_SHIFT 1
50
51 /* Odd/even parity configuration */
52 #define CTRL2_ODD_EVEN_OFFSET 0xC
53 #define CTRL2_ODD_EVEN_MASK 0x04
54 #define CTRL2_ODD_EVEN_SHIFT 2
55
56 /* Baud value higher 5 bits */
57 #define CTRL2_BAUDVALUE_OFFSET 0xC
58 #define CTRL2_BAUDVALUE_MASK 0xF8
59 #define CTRL2_BAUDVALUE_SHIFT 3
60
61 /* Status register */
62 #define StatusReg_REG_OFFSET 0x10
63
64 #define STATUS_REG_OFFSET 0x10
65
66 /* TX ready */
67 #define STATUS_TXRDY_OFFSET 0x10
68 #define STATUS_TXRDY_MASK 0x01
69 #define STATUS_TXRDY_SHIFT 0
70
71 /* Receive full - raised even when 1 char arrived */
72 #define STATUS_RXFULL_OFFSET 0x10
73 #define STATUS_RXFULL_MASK 0x02
74 #define STATUS_RXFULL_SHIFT 1
75
76 /* Parity error */
77 #define STATUS_PARITYERR_OFFSET 0x10
78 #define STATUS_PARITYERR_MASK 0x04
79 #define STATUS_PARITYERR_SHIFT 2
80
81 /* Overflow */
82 #define STATUS_OVERFLOW_OFFSET 0x10
83 #define STATUS_OVERFLOW_MASK 0x08
84 #define STATUS_OVERFLOW_SHIFT 3
85
86 /* Frame error */
87 #define STATUS_FRAMERR_OFFSET 0x10
88 #define STATUS_FRAMERR_MASK 0x10
89 #define STATUS_FRAMERR_SHIFT 4
90
91 /* Data bits length defines */
92 #define DATA_7_BITS 0x00
93 #define DATA_8_BITS 0x01
94
95 /* Parity defines */
96 #define NO_PARITY 0x00
97 #define EVEN_PARITY 0x02
98 #define ODD_PARITY 0x06
99
100 /* Error Status definitions */
101 #define UART_PARITY_ERROR 0x01
102 #define UART_OVERFLOW_ERROR 0x02
103 #define UART_FRAMING_ERROR 0x04
104
105 #define BAUDVALUE_LSB ((uint16_t)(0x00FF))
106 #define BAUDVALUE_MSB ((uint16_t)(0xFF00))
107 #define BAUDVALUE_SHIFT ((uint8_t)(5))
108
109 #define MIV_UART_0_LINECFG 0x1
110
111 #ifdef CONFIG_UART_INTERRUPT_DRIVEN
112 static struct k_thread rx_thread;
113 static K_KERNEL_STACK_DEFINE(rx_stack, 512);
114 #endif
115
116 struct uart_miv_regs_t {
117 uint8_t tx;
118 uint8_t reserved0[3];
119 uint8_t rx;
120 uint8_t reserved1[3];
121 uint8_t ctrlreg1;
122 uint8_t reserved2[3];
123 uint8_t ctrlreg2;
124 uint8_t reserved3[3];
125 uint8_t status;
126 };
127
128 #ifdef CONFIG_UART_INTERRUPT_DRIVEN
129 typedef void (*irq_cfg_func_t)(const struct device *dev);
130 #endif
131
132 struct uart_miv_device_config {
133 uint32_t uart_addr;
134 uint32_t sys_clk_freq;
135 uint32_t line_config;
136 uint32_t baud_rate;
137 #ifdef CONFIG_UART_INTERRUPT_DRIVEN
138 irq_cfg_func_t cfg_func;
139 #endif
140 };
141
142 struct uart_miv_data {
143 #ifdef CONFIG_UART_INTERRUPT_DRIVEN
144 const struct device *dev;
145 uart_irq_callback_user_data_t callback;
146 void *cb_data;
147 #endif
148 };
149
150 #define DEV_UART(dev) \
151 ((struct uart_miv_regs_t *) \
152 ((const struct uart_miv_device_config * const)(dev)->config)->uart_addr)
153
uart_miv_poll_out(const struct device * dev,unsigned char c)154 static void uart_miv_poll_out(const struct device *dev,
155 unsigned char c)
156 {
157 volatile struct uart_miv_regs_t *uart = DEV_UART(dev);
158
159 while (!(uart->status & STATUS_TXRDY_MASK)) {
160 }
161
162 uart->tx = c;
163 }
164
uart_miv_poll_in(const struct device * dev,unsigned char * c)165 static int uart_miv_poll_in(const struct device *dev, unsigned char *c)
166 {
167 volatile struct uart_miv_regs_t *uart = DEV_UART(dev);
168
169 if (uart->status & STATUS_RXFULL_MASK) {
170 *c = (unsigned char)(uart->rx & RXDATA_MASK);
171 return 0;
172 }
173
174 return -1;
175 }
176
uart_miv_err_check(const struct device * dev)177 static int uart_miv_err_check(const struct device *dev)
178 {
179 volatile struct uart_miv_regs_t *uart = DEV_UART(dev);
180 uint32_t flags = uart->status;
181 int err = 0;
182
183 if (flags & STATUS_PARITYERR_MASK) {
184 err |= UART_PARITY_ERROR;
185 }
186
187 if (flags & STATUS_OVERFLOW_MASK) {
188 err |= UART_OVERFLOW_ERROR;
189 }
190
191 if (flags & STATUS_FRAMERR_MASK) {
192 err |= UART_FRAMING_ERROR;
193 }
194
195 return err;
196 }
197
198
199 #ifdef CONFIG_UART_INTERRUPT_DRIVEN
200
uart_miv_fifo_fill(const struct device * dev,const uint8_t * tx_data,int size)201 static int uart_miv_fifo_fill(const struct device *dev,
202 const uint8_t *tx_data,
203 int size)
204 {
205 volatile struct uart_miv_regs_t *uart = DEV_UART(dev);
206 int i;
207
208 for (i = 0; i < size && (uart->status & STATUS_TXRDY_MASK); i++) {
209 uart->tx = tx_data[i];
210 }
211
212 return i;
213 }
214
uart_miv_fifo_read(const struct device * dev,uint8_t * rx_data,const int size)215 static int uart_miv_fifo_read(const struct device *dev,
216 uint8_t *rx_data,
217 const int size)
218 {
219 volatile struct uart_miv_regs_t *uart = DEV_UART(dev);
220 int i;
221
222 for (i = 0; i < size; i++) {
223 if (uart->status & STATUS_RXFULL_MASK) {
224 rx_data[i] = (unsigned char)(uart->rx & RXDATA_MASK);
225 } else {
226 break;
227 }
228 }
229
230 return i;
231 }
232
uart_miv_irq_tx_enable(const struct device * dev)233 static void uart_miv_irq_tx_enable(const struct device *dev)
234 {
235 ARG_UNUSED(dev);
236 }
237
uart_miv_irq_tx_disable(const struct device * dev)238 static void uart_miv_irq_tx_disable(const struct device *dev)
239 {
240 ARG_UNUSED(dev);
241 }
242
uart_miv_irq_tx_ready(const struct device * dev)243 static int uart_miv_irq_tx_ready(const struct device *dev)
244 {
245 volatile struct uart_miv_regs_t *uart = DEV_UART(dev);
246
247 return !(uart->status & STATUS_TXRDY_MASK);
248 }
249
uart_miv_irq_tx_complete(const struct device * dev)250 static int uart_miv_irq_tx_complete(const struct device *dev)
251 {
252 ARG_UNUSED(dev);
253
254 return 1;
255 }
256
uart_miv_irq_rx_enable(const struct device * dev)257 static void uart_miv_irq_rx_enable(const struct device *dev)
258 {
259 ARG_UNUSED(dev);
260 }
261
uart_miv_irq_rx_disable(const struct device * dev)262 static void uart_miv_irq_rx_disable(const struct device *dev)
263 {
264 ARG_UNUSED(dev);
265 }
266
uart_miv_irq_rx_ready(const struct device * dev)267 static int uart_miv_irq_rx_ready(const struct device *dev)
268 {
269 volatile struct uart_miv_regs_t *uart = DEV_UART(dev);
270
271 return !!(uart->status & STATUS_RXFULL_MASK);
272 }
273
uart_miv_irq_err_enable(const struct device * dev)274 static void uart_miv_irq_err_enable(const struct device *dev)
275 {
276 ARG_UNUSED(dev);
277 }
278
uart_miv_irq_err_disable(const struct device * dev)279 static void uart_miv_irq_err_disable(const struct device *dev)
280 {
281 ARG_UNUSED(dev);
282 }
283
uart_miv_irq_is_pending(const struct device * dev)284 static int uart_miv_irq_is_pending(const struct device *dev)
285 {
286 volatile struct uart_miv_regs_t *uart = DEV_UART(dev);
287
288 return !!(uart->status & STATUS_RXFULL_MASK);
289 }
290
uart_miv_irq_update(const struct device * dev)291 static int uart_miv_irq_update(const struct device *dev)
292 {
293 return 1;
294 }
295
uart_miv_irq_handler(const struct device * dev)296 static void uart_miv_irq_handler(const struct device *dev)
297 {
298 struct uart_miv_data *data = dev->data;
299
300 if (data->callback) {
301 data->callback(dev, data->cb_data);
302 }
303 }
304
305 /*
306 * This thread is a workaround for IRQs that are not connected in Mi-V.
307 * Since we cannot rely on IRQs, the rx_thread is working instead and
308 * polling for data. The thread calls the registered callback when data
309 * arrives.
310 */
uart_miv_rx_thread(void * arg1,void * arg2,void * arg3)311 void uart_miv_rx_thread(void *arg1, void *arg2, void *arg3)
312 {
313 struct uart_miv_data *data = (struct uart_miv_data *)arg1;
314 const struct device *dev = data->dev;
315 volatile struct uart_miv_regs_t *uart = DEV_UART(dev);
316 const struct uart_miv_device_config *const cfg = dev->config;
317 /* Make it go to sleep for a period no longer than
318 * time to receive next character.
319 */
320 uint32_t delay = 1000000 / cfg->baud_rate;
321
322 ARG_UNUSED(arg2);
323 ARG_UNUSED(arg3);
324
325 while (1) {
326 if (uart->status & STATUS_RXFULL_MASK) {
327 uart_miv_irq_handler(dev);
328 }
329 k_sleep(K_USEC(delay));
330 }
331 }
332
uart_miv_irq_callback_set(const struct device * dev,uart_irq_callback_user_data_t cb,void * cb_data)333 static void uart_miv_irq_callback_set(const struct device *dev,
334 uart_irq_callback_user_data_t cb,
335 void *cb_data)
336 {
337 struct uart_miv_data *data = dev->data;
338
339 data->callback = cb;
340 data->cb_data = cb_data;
341 }
342
343 #endif /* CONFIG_UART_INTERRUPT_DRIVEN */
344
uart_miv_init(const struct device * dev)345 static int uart_miv_init(const struct device *dev)
346 {
347 const struct uart_miv_device_config *const cfg = dev->config;
348 volatile struct uart_miv_regs_t *uart = DEV_UART(dev);
349 /* Calculate divider value to set baudrate */
350 uint16_t baud_value = (cfg->sys_clk_freq / (cfg->baud_rate * 16U)) - 1;
351
352 /* Set baud rate */
353 uart->ctrlreg1 = (uint8_t)(baud_value & BAUDVALUE_LSB);
354 uart->ctrlreg2 = (uint8_t)(cfg->line_config) |
355 (uint8_t)((baud_value & BAUDVALUE_MSB) >> BAUDVALUE_SHIFT);
356
357 #ifdef CONFIG_UART_INTERRUPT_DRIVEN
358 /* Setup thread polling for data */
359 cfg->cfg_func(dev);
360 #endif
361 return 0;
362 }
363
364 static DEVICE_API(uart, uart_miv_driver_api) = {
365 .poll_in = uart_miv_poll_in,
366 .poll_out = uart_miv_poll_out,
367 .err_check = uart_miv_err_check,
368 #ifdef CONFIG_UART_INTERRUPT_DRIVEN
369 .fifo_fill = uart_miv_fifo_fill,
370 .fifo_read = uart_miv_fifo_read,
371 .irq_tx_enable = uart_miv_irq_tx_enable,
372 .irq_tx_disable = uart_miv_irq_tx_disable,
373 .irq_tx_ready = uart_miv_irq_tx_ready,
374 .irq_tx_complete = uart_miv_irq_tx_complete,
375 .irq_rx_enable = uart_miv_irq_rx_enable,
376 .irq_rx_disable = uart_miv_irq_rx_disable,
377 .irq_rx_ready = uart_miv_irq_rx_ready,
378 .irq_err_enable = uart_miv_irq_err_enable,
379 .irq_err_disable = uart_miv_irq_err_disable,
380 .irq_is_pending = uart_miv_irq_is_pending,
381 .irq_update = uart_miv_irq_update,
382 .irq_callback_set = uart_miv_irq_callback_set,
383 #endif
384 };
385
386 /* This driver is single-instance. */
387 BUILD_ASSERT(DT_NUM_INST_STATUS_OKAY(DT_DRV_COMPAT) <= 1,
388 "unsupported uart_miv instance");
389
390 #if DT_NODE_HAS_STATUS_OKAY(DT_DRV_INST(0))
391
392 static struct uart_miv_data uart_miv_data_0;
393
394 #ifdef CONFIG_UART_INTERRUPT_DRIVEN
395 static void uart_miv_irq_cfg_func_0(const struct device *dev);
396 #endif
397
398 static const struct uart_miv_device_config uart_miv_dev_cfg_0 = {
399 .uart_addr = DT_INST_REG_ADDR(0),
400 .sys_clk_freq = DT_INST_PROP(0, clock_frequency),
401 .line_config = MIV_UART_0_LINECFG,
402 .baud_rate = DT_INST_PROP(0, current_speed),
403 #ifdef CONFIG_UART_INTERRUPT_DRIVEN
404 .cfg_func = uart_miv_irq_cfg_func_0,
405 #endif
406 };
407
408 DEVICE_DT_INST_DEFINE(0, uart_miv_init, NULL,
409 &uart_miv_data_0, &uart_miv_dev_cfg_0,
410 PRE_KERNEL_1, CONFIG_SERIAL_INIT_PRIORITY,
411 (void *)&uart_miv_driver_api);
412
413 #ifdef CONFIG_UART_INTERRUPT_DRIVEN
uart_miv_irq_cfg_func_0(const struct device * dev)414 static void uart_miv_irq_cfg_func_0(const struct device *dev)
415 {
416 struct uart_miv_data *data = dev->data;
417
418 data->dev = dev;
419
420 /* Create a thread which will poll for data - replacement for IRQ */
421 k_thread_create(&rx_thread, rx_stack, 500,
422 uart_miv_rx_thread, data, NULL, NULL, K_PRIO_COOP(2),
423 0, K_NO_WAIT);
424 }
425 #endif
426
427 #endif /* DT_NODE_HAS_STATUS_OKAY(DT_DRV_INST(0)) */
428