1 /*
2 * Copyright 2022 Meta Platforms, Inc. and its affiliates.
3 * SPDX-License-Identifier: Apache-2.0
4 */
5
6 #define DT_DRV_COMPAT cdns_uart
7
8 /**
9 * @brief Serial Driver for cadence UART IP6528
10 */
11
12 #include "uart_cdns.h"
13
14 #define DEV_UART(dev) ((struct uart_cdns_regs *) \
15 ((const struct uart_cdns_device_config *const)(dev)->config)->port)
16
17 /** Check if tx FIFO is full */
uart_cdns_is_tx_fifo_full(struct uart_cdns_regs * uart_regs)18 bool uart_cdns_is_tx_fifo_full(struct uart_cdns_regs *uart_regs)
19 {
20 return ((uart_regs->channel_status & CSR_TFUL_MASK) != 0);
21 }
22
23 /** Check if tx FIFO is empty */
uart_cdns_is_tx_fifo_empty(struct uart_cdns_regs * uart_regs)24 bool uart_cdns_is_tx_fifo_empty(struct uart_cdns_regs *uart_regs)
25 {
26 return ((uart_regs->channel_status & CSR_TEMPTY_MASK) != 0);
27 }
28
29 /** Check if rx FIFO is empty */
uart_cdns_is_rx_fifo_empty(struct uart_cdns_regs * uart_regs)30 bool uart_cdns_is_rx_fifo_empty(struct uart_cdns_regs *uart_regs)
31 {
32 return ((uart_regs->channel_status & CSR_REMPTY_MASK) != 0);
33 }
34
35 /** Set the baudrate */
uart_cdns_set_baudrate(struct uart_cdns_regs * uart_regs,const struct uart_cdns_device_config * const dev_cfg,uint32_t baud_rate)36 void uart_cdns_set_baudrate(struct uart_cdns_regs *uart_regs,
37 const struct uart_cdns_device_config *const dev_cfg,
38 uint32_t baud_rate)
39 {
40 uart_regs->baud_rate_div = dev_cfg->bdiv;
41
42 /*
43 * baud_rate is calculated by hardware as below
44 *
45 * baud_rate = sel_clk / ((bdiv + 1) * clock_divisor)
46 * i.e. clock_divisor = sel_clk / ((bdiv + 1) * baud_rate)
47 *
48 * However to round to a nearest integer we use this:
49 * clock_divisor = (sel_clk + ((bdiv + 1) * baud_rate) / 2) / ((bdiv + 1) * baud_rate)
50 */
51 uart_regs->baud_rate_gen = (dev_cfg->sys_clk_freq + ((dev_cfg->bdiv + 1) * baud_rate) / 2) /
52 ((dev_cfg->bdiv + 1) * baud_rate);
53 }
54
uart_cdns_poll_out(const struct device * dev,unsigned char out_char)55 static void uart_cdns_poll_out(const struct device *dev, unsigned char out_char)
56 {
57 struct uart_cdns_regs *uart_regs = DEV_UART(dev);
58 /* Wait while TX FIFO is full */
59 while (uart_cdns_is_tx_fifo_full(uart_regs)) {
60 }
61 uart_regs->rx_tx_fifo = (uint32_t)out_char;
62 }
63
64 /** @brief Poll the device for input. */
uart_cdns_poll_in(const struct device * dev,unsigned char * p_char)65 int uart_cdns_poll_in(const struct device *dev, unsigned char *p_char)
66 {
67 struct uart_cdns_regs *uart_regs = DEV_UART(dev);
68
69 if (uart_cdns_is_rx_fifo_empty(uart_regs)) {
70 return -1;
71 }
72
73 *p_char = (unsigned char)(uart_regs->rx_tx_fifo & RXDATA_MASK);
74 return 0;
75 }
76
77 #ifdef CONFIG_UART_INTERRUPT_DRIVEN
uart_cdns_fill_fifo(const struct device * dev,const uint8_t * tx_data,int len)78 static int uart_cdns_fill_fifo(const struct device *dev, const uint8_t *tx_data, int len)
79 {
80 struct uart_cdns_regs *uart_regs = DEV_UART(dev);
81
82 int i = 0;
83
84 for (i = 0; i < len && (!uart_cdns_is_tx_fifo_full(uart_regs)); i++) {
85 uart_regs->rx_tx_fifo = tx_data[i];
86 while (!uart_cdns_is_tx_fifo_empty(uart_regs)) {
87 }
88 }
89 return i;
90 }
91
uart_cdns_read_fifo(const struct device * dev,uint8_t * rx_data,const int size)92 static int uart_cdns_read_fifo(const struct device *dev, uint8_t *rx_data, const int size)
93 {
94 struct uart_cdns_regs *uart_regs = DEV_UART(dev);
95
96 int i = 0;
97
98 for (i = 0; i < size && (!uart_cdns_is_rx_fifo_empty(uart_regs)); i++) {
99 rx_data[i] = uart_regs->rx_tx_fifo;
100 }
101 if (i > 0) {
102 uart_regs->ctrl |= CTRL_RSTTO_MASK;
103 }
104 return i;
105 }
106
uart_cdns_enable_tx_irq(const struct device * dev)107 void uart_cdns_enable_tx_irq(const struct device *dev)
108 {
109 struct uart_cdns_regs *uart_regs = DEV_UART(dev);
110
111 uart_regs->intr_enable |= CSR_TTRIG_MASK;
112 }
113
uart_cdns_disable_tx_irq(const struct device * dev)114 void uart_cdns_disable_tx_irq(const struct device *dev)
115 {
116 struct uart_cdns_regs *uart_regs = DEV_UART(dev);
117
118 uart_regs->intr_disable |= CSR_TTRIG_MASK;
119 }
120
uart_cdns_irq_tx_ready(const struct device * dev)121 static int uart_cdns_irq_tx_ready(const struct device *dev)
122 {
123 return !uart_cdns_is_tx_fifo_full(DEV_UART(dev));
124 }
125
uart_cdns_irq_tx_complete(const struct device * dev)126 static int uart_cdns_irq_tx_complete(const struct device *dev)
127 {
128 return uart_cdns_is_tx_fifo_empty(DEV_UART(dev));
129 }
130
uart_cdns_enable_rx_irq(const struct device * dev)131 void uart_cdns_enable_rx_irq(const struct device *dev)
132 {
133 struct uart_cdns_regs *uart_regs = DEV_UART(dev);
134
135 uart_regs->rx_timeout = DEFAULT_RTO_PERIODS_FACTOR;
136 uart_regs->intr_enable |= (CSR_RTRIG_MASK | CSR_RBRK_MASK | CSR_TOUT_MASK);
137 }
138
139 /** Disable RX UART interrupt */
uart_cdns_disable_rx_irq(const struct device * dev)140 void uart_cdns_disable_rx_irq(const struct device *dev)
141 {
142 struct uart_cdns_regs *uart_regs = DEV_UART(dev);
143
144 uart_regs->intr_disable |= (CSR_RTRIG_MASK | CSR_RBRK_MASK | CSR_TOUT_MASK);
145 }
146
uart_cdns_irq_rx_ready(const struct device * dev)147 static int uart_cdns_irq_rx_ready(const struct device *dev)
148 {
149 return !uart_cdns_is_rx_fifo_empty(DEV_UART(dev));
150 }
151
uart_cdns_enable_irq_err(const struct device * dev)152 static void uart_cdns_enable_irq_err(const struct device *dev)
153 {
154 struct uart_cdns_regs *uart_regs = DEV_UART(dev);
155
156 uart_regs->intr_enable |=
157 (CSR_TOVR_MASK | CSR_TOUT_MASK | CSR_PARE_MASK | CSR_FRAME_MASK | CSR_ROVR_MASK);
158 }
159
uart_cdns_disable_irq_err(const struct device * dev)160 static void uart_cdns_disable_irq_err(const struct device *dev)
161 {
162 struct uart_cdns_regs *uart_regs = DEV_UART(dev);
163
164 uart_regs->intr_disable |=
165 (CSR_TOVR_MASK | CSR_TOUT_MASK | CSR_PARE_MASK | CSR_FRAME_MASK | CSR_ROVR_MASK);
166 }
167
uart_cdns_is_irq_pending(const struct device * dev)168 static int uart_cdns_is_irq_pending(const struct device *dev)
169 {
170 struct uart_cdns_regs *uart_regs = DEV_UART(dev);
171
172 return (uart_regs->channel_intr_status != 0);
173 }
174
175 /** Check for IRQ updates */
uart_cdns_update_irq(const struct device * dev)176 static int uart_cdns_update_irq(const struct device *dev)
177 {
178 return 1;
179 }
180
181 /** Set the callback function pointer for IRQ. */
uart_cdns_set_irq_callback(const struct device * dev,uart_irq_callback_user_data_t cb,void * cb_data)182 void uart_cdns_set_irq_callback(const struct device *dev, uart_irq_callback_user_data_t cb,
183 void *cb_data)
184 {
185 struct uart_cdns_data *data;
186
187 data = dev->data;
188 data->callback = cb;
189 data->cb_data = cb_data;
190 }
191
uart_cdns_irq_handler(const struct device * dev)192 static void uart_cdns_irq_handler(const struct device *dev)
193 {
194 struct uart_cdns_regs *uart_regs = DEV_UART(dev);
195 uint32_t key = irq_lock();
196 uint32_t isr_status;
197 struct uart_cdns_data *data = dev->data;
198
199 if (data->callback) {
200 data->callback(dev, data->cb_data);
201 }
202
203 /* clear events */
204 /* need to make local copy of the status */
205 isr_status = uart_regs->channel_intr_status;
206
207 irq_unlock(key);
208 }
209
210 #endif
211
212 static const struct uart_driver_api uart_cdns_driver_api = {
213 .poll_in = uart_cdns_poll_in,
214 .poll_out = uart_cdns_poll_out,
215 #ifdef CONFIG_UART_INTERRUPT_DRIVEN
216 .fifo_fill = uart_cdns_fill_fifo,
217 .fifo_read = uart_cdns_read_fifo,
218 .irq_tx_enable = uart_cdns_enable_tx_irq,
219 .irq_tx_disable = uart_cdns_disable_tx_irq,
220 .irq_tx_ready = uart_cdns_irq_tx_ready,
221 .irq_tx_complete = uart_cdns_irq_tx_complete,
222 .irq_rx_enable = uart_cdns_enable_rx_irq,
223 .irq_rx_disable = uart_cdns_disable_rx_irq,
224 .irq_rx_ready = uart_cdns_irq_rx_ready,
225 .irq_err_enable = uart_cdns_enable_irq_err,
226 .irq_err_disable = uart_cdns_disable_irq_err,
227 .irq_is_pending = uart_cdns_is_irq_pending,
228 .irq_update = uart_cdns_update_irq,
229 .irq_callback_set = uart_cdns_set_irq_callback
230 #endif
231 };
232
233 /** Initialize the UART */
uart_cdns_init(const struct device * dev)234 static int uart_cdns_init(const struct device *dev)
235 {
236 struct uart_cdns_regs *uart_regs = DEV_UART(dev);
237 const struct uart_cdns_device_config *const dev_cfg = dev->config;
238
239 /* Reset RX and TX path */
240 uart_regs->ctrl = (CTRL_RXRES_MASK | CTRL_TXRES_MASK);
241
242 /* Disable TX and RX channels */
243 uart_regs->ctrl = (CTRL_STPBRK_MASK | CTRL_TXDIS_MASK | CTRL_RXDIS_MASK);
244
245 /* Configure Baud rate */
246 uart_cdns_set_baudrate(uart_regs, dev_cfg, dev_cfg->baud_rate);
247
248 /* Configure the mode */
249 uart_regs->mode = (SET_VAL32(MODE_WSIZE, 1) | SET_VAL32(MODE_UCLKEN, 1) |
250 SET_VAL32(MODE_PAR, dev_cfg->parity));
251
252 /* Disable all interrupts */
253 uart_regs->intr_disable = 0xFFFFFFFF;
254
255 /* Enable TX and RX Channels */
256 uart_regs->ctrl = (CTRL_TXEN_MASK | CTRL_RXEN_MASK | CTRL_STPBRK_MASK);
257
258 if (dev_cfg->cfg_func) {
259 /* Setup IRQ handler */
260 dev_cfg->cfg_func();
261 }
262
263 return 0;
264 }
265
266 #ifdef CONFIG_UART_INTERRUPT_DRIVEN
267
268 #define UART_CDNS_IRQ_CFG_FUNC(n) \
269 static void uart_cdns_irq_cfg_func_##n(void) \
270 { \
271 IRQ_CONNECT(DT_INST_IRQN(n), DT_INST_IRQ(n, priority), uart_cdns_irq_handler, \
272 DEVICE_DT_INST_GET(n), 0); \
273 \
274 irq_enable(DT_INST_IRQN(n)); \
275 }
276
277 #define UART_CDNS_IRQ_CFG_FUNC_INIT(n) .cfg_func = uart_cdns_irq_cfg_func_##n,
278
279 #else
280
281 #define UART_CDNS_IRQ_CFG_FUNC(n)
282 #define UART_CDNS_IRQ_CFG_FUNC_INIT(n)
283
284 #endif
285
286 #define UART_CDNS_INIT(n) \
287 static struct uart_cdns_data uart_cdns_data_##n; \
288 \
289 UART_CDNS_IRQ_CFG_FUNC(n) \
290 \
291 static const struct uart_cdns_device_config uart_cdns_dev_cfg_##n = { \
292 .port = DT_INST_REG_ADDR(n), \
293 .bdiv = DT_INST_PROP(n, bdiv), \
294 .sys_clk_freq = DT_INST_PROP(n, clock_frequency), \
295 .baud_rate = DT_INST_PROP(n, current_speed), \
296 .parity = CDNS_PARTITY_MAP(DT_ENUM_IDX(DT_DRV_INST(n), parity)), \
297 UART_CDNS_IRQ_CFG_FUNC_INIT(n)}; \
298 \
299 DEVICE_DT_INST_DEFINE(n, uart_cdns_init, NULL, &uart_cdns_data_##n, \
300 &uart_cdns_dev_cfg_##n, PRE_KERNEL_1, \
301 CONFIG_KERNEL_INIT_PRIORITY_DEVICE, &uart_cdns_driver_api);
302
303 DT_INST_FOREACH_STATUS_OKAY(UART_CDNS_INIT)
304