1 /*
2  * Copyright (c) 2006-2024, RT-Thread Development Team
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  *
6  * Change Logs:
7  * Date           Author       Notes
8  * 2024-04-11     liYony       the first version
9  */
10 
11 #include <rthw.h>
12 #include <rtdevice.h>
13 #include <drv_uart.h>
14 #include "board.h"
15 #include "zynqmp_uart.h"
16 
17 #define ZYNQMP_UART_DEVICE_DEFAULT(base, irq, clk) {{   \
18         .ops = &_zynqmp_ops,                            \
19         .config = RT_SERIAL_CONFIG_DEFAULT              \
20     },                                                  \
21     .hw_base = base,                                    \
22     .irqno = irq,                                       \
23     .in_clk = clk                                       \
24 }
25 
26 struct zynqmp_uart_device
27 {
28     struct rt_serial_device device;
29     rt_ubase_t hw_base;
30     rt_uint32_t irqno;
31     rt_uint32_t in_clk;
32 };
33 
_uart_set_fifo_threshold(rt_ubase_t base,rt_uint8_t trigger_level)34 static void _uart_set_fifo_threshold(rt_ubase_t base, rt_uint8_t trigger_level)
35 {
36     rt_uint32_t reg_triger;
37 
38     /* Assert validates the input arguments */
39     RT_ASSERT(base != RT_NULL);
40     RT_ASSERT(trigger_level <= (rt_uint8_t)XUARTPS_RXWM_MASK);
41 
42     reg_triger = ((rt_uint32_t)trigger_level) & (rt_uint32_t)XUARTPS_RXWM_MASK;
43 
44     /*
45      * Write the new value for the FIFO control register to it such that the
46      * threshold is changed
47      */
48     writel(reg_triger, base + XUARTPS_RXWM_OFFSET);
49 }
50 
_uart_set_interrupt_mask(rt_ubase_t base,rt_uint32_t mask)51 static void _uart_set_interrupt_mask(rt_ubase_t base, rt_uint32_t mask)
52 {
53     rt_uint32_t temp_mask = mask;
54 
55     RT_ASSERT(base != RT_NULL);
56 
57     temp_mask &= (rt_uint32_t)XUARTPS_IXR_MASK;
58 
59     writel(temp_mask, base + XUARTPS_IER_OFFSET);
60     writel((~temp_mask), base + XUARTPS_IDR_OFFSET);
61 }
62 
_uart_baudrate_init(rt_ubase_t base,struct serial_configure * cfg,rt_uint32_t in_clk)63 static rt_err_t _uart_baudrate_init(rt_ubase_t base, struct serial_configure *cfg, rt_uint32_t in_clk)
64 {
65     rt_uint32_t iter_baud_div;     /* Iterator for available baud divisor values */
66     rt_uint32_t brgr_value;        /* Calculated value for baud rate generator */
67     rt_uint32_t calc_baudrate;     /* Calculated baud rate */
68     rt_uint32_t baud_error;        /* Diff between calculated and requested baud rate */
69     rt_uint32_t best_brgr = 0U;    /* Best value for baud rate generator */
70     rt_uint8_t best_baud_div = 0U; /* Best value for baud divisor */
71     rt_uint32_t best_error = 0xFFFFFFFFU;
72     rt_uint32_t percent_error;
73     rt_uint32_t mode_reg;
74     rt_uint32_t input_clk;
75     rt_uint32_t temp_reg;
76 
77     /* Asserts validate the input arguments */
78     RT_ASSERT(base != RT_NULL);
79     RT_ASSERT(cfg->baud_rate <= (rt_uint32_t)XUARTPS_MAX_RATE);
80     RT_ASSERT(cfg->baud_rate >= (rt_uint32_t)XUARTPS_MIN_RATE);
81 
82     /*
83      * Make sure the baud rate is not impossilby large.
84      * Fastest possible baud rate is Input Clock / 2.
85      */
86     if ((cfg->baud_rate * 2) > in_clk)
87     {
88         return -RT_EINVAL;
89     }
90     /* Check whether the input clock is divided by 8 */
91     mode_reg = readl(base + XUARTPS_MR_OFFSET);
92 
93     input_clk = in_clk;
94     if (mode_reg & XUARTPS_MR_CLKSEL)
95     {
96         input_clk = in_clk / 8;
97     }
98 
99     /*
100      * Determine the Baud divider. It can be 4to 254.
101      * Loop through all possible combinations
102      */
103     for (iter_baud_div = 4; iter_baud_div < 255; iter_baud_div++)
104     {
105 
106         /* Calculate the value for BRGR register */
107         brgr_value = input_clk / (cfg->baud_rate * (iter_baud_div + 1));
108 
109         /* Calculate the baud rate from the BRGR value */
110         calc_baudrate = input_clk / (brgr_value * (iter_baud_div + 1));
111 
112         /* Avoid unsigned integer underflow */
113         if (cfg->baud_rate > calc_baudrate)
114         {
115             baud_error = cfg->baud_rate - calc_baudrate;
116         }
117         else
118         {
119             baud_error = calc_baudrate - cfg->baud_rate;
120         }
121 
122         /* Find the calculated baud rate closest to requested baud rate. */
123         if (best_error > baud_error)
124         {
125 
126             best_brgr = brgr_value;
127             best_baud_div = iter_baud_div;
128             best_error = baud_error;
129         }
130     }
131 
132     /* Make sure the best error is not too large. */
133     percent_error = (best_error * 100) / cfg->baud_rate;
134     if (XUARTPS_MAX_BAUD_ERROR_RATE < percent_error)
135     {
136         return -RT_EINVAL;
137     }
138 
139     /* Disable TX and RX to avoid glitches when setting the baud rate. */
140     temp_reg = (((readl(base + XUARTPS_CR_OFFSET)) & ((rt_uint32_t)(~XUARTPS_CR_EN_DIS_MASK))) |
141                 ((rt_uint32_t)XUARTPS_CR_RX_DIS | (rt_uint32_t)XUARTPS_CR_TX_DIS));
142     writel(temp_reg, base + XUARTPS_CR_OFFSET);
143 
144     /* Set the baud rate divisor */
145     writel(best_brgr, base + XUARTPS_BAUDGEN_OFFSET);
146     writel(best_baud_div, base + XUARTPS_BAUDDIV_OFFSET);
147 
148     /* RX and TX SW reset */
149     writel(XUARTPS_CR_TXRST | XUARTPS_CR_RXRST, base + XUARTPS_CR_OFFSET);
150 
151     /* Enable device */
152     temp_reg = (((readl(base + XUARTPS_CR_OFFSET)) & ((rt_uint32_t)(~XUARTPS_CR_EN_DIS_MASK))) |
153                 ((rt_uint32_t)XUARTPS_CR_RX_EN | (rt_uint32_t)XUARTPS_CR_TX_EN));
154     writel(temp_reg, base + XUARTPS_CR_OFFSET);
155 
156     return RT_EOK;
157 }
158 
zynqmp_uart_configure(struct rt_serial_device * serial,struct serial_configure * cfg)159 static rt_err_t zynqmp_uart_configure(struct rt_serial_device *serial, struct serial_configure *cfg)
160 {
161     struct zynqmp_uart_device *uart = (struct zynqmp_uart_device *)serial;
162 
163     RT_ASSERT(uart != RT_NULL);
164 
165     if (_uart_baudrate_init(uart->hw_base, cfg, uart->in_clk) != RT_EOK)
166     {
167         return -RT_ERROR;
168     }
169 
170     rt_uint32_t mode_reg = 0U;
171 
172     /* Set the parity mode */
173     mode_reg = readl(uart->hw_base + XUARTPS_MR_OFFSET);
174 
175     /* Mask off what's already there */
176     mode_reg &= (~((rt_uint32_t)XUARTPS_MR_CHARLEN_MASK |
177                    (rt_uint32_t)XUARTPS_MR_STOPMODE_MASK |
178                    (rt_uint32_t)XUARTPS_MR_PARITY_MASK));
179 
180     switch (cfg->data_bits)
181     {
182     case DATA_BITS_6:
183         mode_reg |= (rt_uint32_t)XUARTPS_MR_CHARLEN_6_BIT;
184         break;
185     case DATA_BITS_7:
186         mode_reg |= (rt_uint32_t)XUARTPS_MR_CHARLEN_7_BIT;
187         break;
188     case DATA_BITS_8:
189         mode_reg |= (rt_uint32_t)XUARTPS_MR_CHARLEN_8_BIT;
190         break;
191     default:
192         mode_reg |= (rt_uint32_t)XUARTPS_MR_CHARLEN_8_BIT;
193         break;
194     }
195 
196     switch (cfg->stop_bits)
197     {
198     case STOP_BITS_1:
199         mode_reg |= (rt_uint32_t)XUARTPS_MR_STOPMODE_1_BIT;
200         break;
201     case STOP_BITS_2:
202         mode_reg |= (rt_uint32_t)XUARTPS_MR_STOPMODE_2_BIT;
203         break;
204     default:
205         mode_reg |= (rt_uint32_t)XUARTPS_MR_STOPMODE_1_BIT;
206         break;
207     }
208 
209     switch (cfg->parity)
210     {
211     case PARITY_NONE:
212         mode_reg |= (rt_uint32_t)XUARTPS_MR_PARITY_NONE;
213         break;
214     case PARITY_ODD:
215         mode_reg |= (rt_uint32_t)XUARTPS_MR_PARITY_ODD;
216         break;
217     case PARITY_EVEN:
218         mode_reg |= (rt_uint32_t)XUARTPS_MR_PARITY_EVEN;
219         break;
220     default:
221         mode_reg |= (rt_uint32_t)XUARTPS_MR_PARITY_NONE;
222         break;
223     }
224 
225     /* Write the mode register out */
226     writel(mode_reg, uart->hw_base + XUARTPS_MR_OFFSET);
227 
228     /* Set the RX FIFO trigger at 8 data bytes. */
229     writel(0x08U, uart->hw_base + XUARTPS_RXWM_OFFSET);
230 
231     /* Set the RX timeout to 1, which will be 4 character time */
232     writel(0x01U, uart->hw_base + XUARTPS_RXTOUT_OFFSET);
233 
234     /* Disable all interrupts, polled mode is the default */
235     writel(XUARTPS_IXR_MASK, uart->hw_base + XUARTPS_IDR_OFFSET);
236 
237     return RT_EOK;
238 }
239 
zynqmp_uart_control(struct rt_serial_device * serial,int cmd,void * arg)240 static rt_err_t zynqmp_uart_control(struct rt_serial_device *serial, int cmd, void *arg)
241 {
242     struct zynqmp_uart_device *uart = (struct zynqmp_uart_device *)serial;
243 
244     RT_ASSERT(uart != RT_NULL);
245 
246     switch (cmd)
247     {
248     case RT_DEVICE_CTRL_CLR_INT:
249         /* Disable the UART Interrupt */
250         rt_hw_interrupt_mask(uart->irqno);
251         _uart_set_interrupt_mask(uart->hw_base, 0U);
252         break;
253     case RT_DEVICE_CTRL_SET_INT:
254         /* Enable the UART Interrupt */
255         _uart_set_fifo_threshold(uart->hw_base, 1);
256         rt_hw_interrupt_umask(uart->irqno);
257         _uart_set_interrupt_mask(uart->hw_base, XUARTPS_IXR_RXOVR);
258         break;
259     }
260 
261     return RT_EOK;
262 }
263 
zynqmp_uart_putc(struct rt_serial_device * serial,char c)264 static int zynqmp_uart_putc(struct rt_serial_device *serial, char c)
265 {
266     struct zynqmp_uart_device *uart = (struct zynqmp_uart_device *)serial;
267 
268     RT_ASSERT(uart != RT_NULL);
269 
270     /* Wait until there is space in TX FIFO */
271     while ((readl(uart->hw_base + XUARTPS_SR_OFFSET) &
272             XUARTPS_SR_TXFULL) == XUARTPS_SR_TXFULL)
273     {
274         ;
275     }
276 
277     /* Write the byte into the TX FIFO */
278     writel((rt_uint32_t)c, uart->hw_base + XUARTPS_FIFO_OFFSET);
279 
280     return 1;
281 }
282 
zynqmp_uart_getc(struct rt_serial_device * serial)283 static int zynqmp_uart_getc(struct rt_serial_device *serial)
284 {
285     struct zynqmp_uart_device *uart = (struct zynqmp_uart_device *)serial;
286 
287     RT_ASSERT(uart != RT_NULL);
288 
289     /* Wait until there is data */
290     if ((readl(uart->hw_base + XUARTPS_SR_OFFSET) &
291          XUARTPS_SR_RXEMPTY) == XUARTPS_SR_RXEMPTY)
292     {
293         return -1;
294     }
295 
296     int ch = readl(uart->hw_base + XUARTPS_FIFO_OFFSET);
297 
298     return ch;
299 }
300 
301 static const struct rt_uart_ops _zynqmp_ops =
302 {
303     zynqmp_uart_configure,
304     zynqmp_uart_control,
305     zynqmp_uart_putc,
306     zynqmp_uart_getc,
307 };
308 
309 #ifdef BSP_USING_UART0
310 static struct zynqmp_uart_device _uart0_device =
311     ZYNQMP_UART_DEVICE_DEFAULT(ZYNQMP_UART0_BASE, ZYNQMP_UART0_IRQNUM, ZYNQMP_UART0_CLK_FREQ_HZ);
312 #endif
313 
rt_hw_uart_isr(int irqno,void * param)314 static void rt_hw_uart_isr(int irqno, void *param)
315 {
316     struct zynqmp_uart_device *uart = (struct zynqmp_uart_device *)param;
317 
318     RT_ASSERT(uart != RT_NULL);
319     struct rt_serial_device *serial = &(uart->device);
320     rt_uint32_t isr_status;
321 
322     isr_status = readl(uart->hw_base + XUARTPS_IMR_OFFSET);
323     isr_status &= readl(uart->hw_base + XUARTPS_ISR_OFFSET);
324     if (isr_status & (rt_uint32_t)XUARTPS_IXR_RXOVR)
325     {
326         writel(XUARTPS_IXR_RXOVR, uart->hw_base + XUARTPS_ISR_OFFSET);
327         rt_hw_serial_isr(serial, RT_SERIAL_EVENT_RX_IND);
328     }
329 }
330 
rt_hw_uart_init(void)331 int rt_hw_uart_init(void)
332 {
333     struct zynqmp_uart_device *uart = RT_NULL;
334 
335 #ifdef BSP_USING_UART0
336     uart = &_uart0_device;
337     _uart0_device.hw_base = (rt_size_t)rt_ioremap((void*)_uart0_device.hw_base, ZYNQMP_UART0_SIZE);
338     /* register UART0 device */
339     rt_hw_serial_register(&uart->device, "uart0",
340                           RT_DEVICE_FLAG_RDWR | RT_DEVICE_FLAG_INT_RX,
341                           uart);
342     rt_hw_interrupt_install(uart->irqno, rt_hw_uart_isr, uart, "uart0");
343 #endif
344 
345     return 0;
346 }
347