1 /*
2  * Copyright (c) 2006-2021, RT-Thread Development Team
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  *
6  * Change Logs:
7  * Date           Author       Notes
8  * 2020-03-19     WangHuachen  the first version
9  */
10 
11 #include <rthw.h>
12 #include <rtdevice.h>
13 
14 #include "board.h"
15 #include "gic.h"
16 
17 #include "drv_uart.h"
18 
19 #define IOU_SLCR_BASE_ADDR   XPAR_PSU_IOUSLCR_0_S_AXI_BASEADDR
20 #define ZynqMP_IOU_SLCR_MIO_PIN(x)     (IOU_SLCR_BASE_ADDR + 0x04 * x)
21 
22 #define XUARTPS_MAX_RATE    921600U
23 #define XUARTPS_MIN_RATE    110U
24 #define XUARTPS_MAX_BAUD_ERROR_RATE     3U    /* max % error allowed */
25 
26 #define ZynqMP_UART_INT_DISABLE(UART)       \
27     (UART->IER &= ~(UART_IXR_RXOVR | UART_IXR_RXFULL))
28 #define ZynqMP_UART_INT_ENABLE(UART)        \
29     (UART->IER |= (UART_IXR_RXOVR | UART_IXR_RXFULL))
30 
31 #define ZynqMP_UART_SENDCHAR(UART, ch)          \
32     do {                                     \
33         while ((UART->SR) & UART_SR_TXFULL); \
34         UART->FIFO = ch;                     \
35     } while(0)
36 
37 #define ZynqMP_UART_GETCHAR(UART, ch)                          \
38     do {                                                    \
39         if (UART->ISR & UART_IXR_RXOVR)                      \
40         {                                                   \
41             ch = UART->FIFO & 0xff;                         \
42             UART->ISR = (UART_IXR_RXOVR | UART_IXR_RXFULL); \
43         }                                                   \
44     } while(0)
45 
UartEnable(UART_Registers * uart)46 static void UartEnable(UART_Registers* uart)
47 {
48     uint32_t tmp = uart->CR;
49     tmp &= ~UART_CR_EN_DIS_MASK;
50     tmp |= (UART_CR_TX_EN | UART_CR_RX_EN);
51 
52     uart->CR = tmp;
53 }
54 
UartDisable(UART_Registers * uart)55 static void UartDisable(UART_Registers* uart)
56 {
57     uint32_t tmp = uart->CR;
58     tmp &= ~UART_CR_EN_DIS_MASK;
59     tmp |= (UART_CR_TX_DIS | UART_CR_RX_DIS);
60     uart->CR = tmp;
61 }
62 
UartResetTXRXLogic(UART_Registers * uart)63 static void UartResetTXRXLogic(UART_Registers* uart)
64 {
65     uart->CR |= (UART_CR_TXRST | UART_CR_RXRST);
66     while (uart->CR & (UART_CR_TXRST | UART_CR_RXRST));
67 }
68 
69 /*                     UART TxD/RxD |   L3 Mux   |   L2 Mux    |  L1 Mux  */
70 #define RX_MIO_PIN_MODE ((0x6 << 5) | (0x0 << 3) | (0x0 << 2) | (0x0 << 1))
71 #define TX_MIO_PIN_MODE ((0x6 << 5) | (0x0 << 3) | (0x0 << 2) | (0x0 << 1))
72 
73 struct hw_uart_device
74 {
75     UART_Registers * uart;
76     rt_uint32_t irqno;
77     rt_uint32_t inputClockHz;
78 
79     /* MIO pin mode address */
80     rt_uint32_t *rxmio;
81     rt_uint32_t *txmio;
82 };
83 
84 /* RT-Thread UART interface */
85 
rt_hw_uart_isr(int irqno,void * param)86 static void rt_hw_uart_isr(int irqno, void *param)
87 {
88     struct rt_serial_device *serial = (struct rt_serial_device *)param;
89 
90     rt_hw_serial_isr(serial, RT_SERIAL_EVENT_RX_IND);
91 }
92 
XUartPsSetBandRate(struct hw_uart_device * pdev,rt_uint32_t targetBandRate)93 static rt_err_t XUartPsSetBandRate(struct hw_uart_device *pdev, rt_uint32_t targetBandRate)
94 {
95     rt_uint32_t IterBAUDDIV;    /* Iterator for available baud divisor values */
96     rt_uint32_t BRGR_Value;        /* Calculated value for baud rate generator */
97     rt_uint32_t CalcBaudRate;    /* Calculated baud rate */
98     rt_uint32_t BaudError;        /* Diff between calculated and requested baud rate */
99     rt_uint32_t Best_BRGR = 0U;    /* Best value for baud rate generator */
100     rt_uint8_t Best_BAUDDIV = 0U;    /* Best value for baud divisor */
101     rt_uint32_t Best_Error = 0xFFFFFFFFU;
102     rt_uint32_t PercentError;
103     rt_uint32_t ModeReg;
104     rt_uint32_t InputClk;
105 
106     if ((targetBandRate > (rt_uint32_t)XUARTPS_MAX_RATE) ||
107         (targetBandRate < (rt_uint32_t)XUARTPS_MIN_RATE))
108         return -RT_EINVAL;
109     /*
110      * Make sure the baud rate is not impossilby large.
111      * Fastest possible baud rate is Input Clock / 2.
112      */
113     if ((targetBandRate * 2) > pdev->inputClockHz)
114         return -RT_EINVAL;
115 
116     /* Check whether the input clock is divided by 8 */
117     ModeReg = pdev->uart->MR;
118     InputClk = pdev->inputClockHz;
119     if(ModeReg & UART_MR_CLKSEL)
120         InputClk = pdev->inputClockHz / 8;
121 
122     /*
123      * Determine the Baud divider. It can be 4to 254.
124      * Loop through all possible combinations
125      */
126     for (IterBAUDDIV = 4; IterBAUDDIV < 255; IterBAUDDIV++)
127     {
128         /* Calculate the value for BRGR register */
129         BRGR_Value = InputClk / (targetBandRate * (IterBAUDDIV + 1));
130 
131         /* Calculate the baud rate from the BRGR value */
132         CalcBaudRate = InputClk / (BRGR_Value * (IterBAUDDIV + 1));
133 
134         /* Avoid unsigned integer underflow */
135         if (targetBandRate > CalcBaudRate)
136             BaudError = targetBandRate - CalcBaudRate;
137         else
138             BaudError = CalcBaudRate - targetBandRate;
139 
140         /* Find the calculated baud rate closest to requested baud rate. */
141         if (Best_Error > BaudError)
142         {
143             Best_BRGR = BRGR_Value;
144             Best_BAUDDIV = IterBAUDDIV;
145             Best_Error = BaudError;
146         }
147     }
148 
149     /* Make sure the best error is not too large. */
150     PercentError = (Best_Error * 100) / targetBandRate;
151     if (XUARTPS_MAX_BAUD_ERROR_RATE < PercentError)
152         return -RT_ERROR;
153 
154     pdev->uart->BAUDGEN = Best_BRGR;
155     pdev->uart->BAUDDIV = Best_BAUDDIV;
156     return RT_EOK;
157 }
158 
uart_configure(struct rt_serial_device * serial,struct serial_configure * cfg)159 static rt_err_t uart_configure(struct rt_serial_device *serial, struct serial_configure *cfg)
160 {
161     uint32_t mr;
162     struct hw_uart_device *pdev = serial->parent.user_data;
163     UART_Registers *uart = pdev->uart;
164 
165     UartDisable(uart);
166     UartResetTXRXLogic(uart);
167     UartEnable(uart);
168 
169     mr = uart->MR & ~(UART_MR_CHARLEN_MASK |
170                       UART_MR_STOPMODE_MASK |
171                       UART_MR_PARITY_MASK);
172 
173     if (cfg->stop_bits == STOP_BITS_2)
174         mr |= UART_MR_STOPMODE_2_BIT;
175     else if (cfg->stop_bits == STOP_BITS_1)
176         mr |= UART_MR_STOPMODE_1_BIT;
177     else
178         return -RT_EINVAL;
179 
180     if (cfg->parity == PARITY_EVEN)
181         mr |= UART_MR_PARITY_EVEN;
182     else if (cfg->parity == PARITY_ODD)
183         mr |= UART_MR_PARITY_ODD;
184     else if (cfg->parity == PARITY_NONE)
185         mr |= UART_MR_PARITY_NONE;
186     else
187         return -RT_EINVAL;
188 
189     if (cfg->data_bits == DATA_BITS_8)
190         mr |= UART_MR_CHARLEN_8_BIT;
191     else if (cfg->data_bits == DATA_BITS_7)
192         mr |= UART_MR_CHARLEN_7_BIT;
193     else if (cfg->data_bits == DATA_BITS_6)
194         mr |= UART_MR_CHARLEN_6_BIT;
195     else
196         return -RT_EINVAL;
197 
198     uart->MR = mr;
199 
200     uart->TXWM = 8;
201     uart->RXWM = 1;
202 
203     if (XUartPsSetBandRate(pdev, cfg->baud_rate) != RT_EOK)
204     {
205         rt_kprintf("baudrate %d not implemented yet\n", cfg->baud_rate);
206         return -RT_EINVAL;
207     }
208 
209     /* disable all interrupts */
210     uart->IDR = UART_IXR_MASK;
211 
212     /* configure the pin */
213     *(pdev->txmio) = TX_MIO_PIN_MODE;
214     *(pdev->rxmio) = RX_MIO_PIN_MODE;
215 
216     return RT_EOK;
217 }
218 
uart_control(struct rt_serial_device * serial,int cmd,void * arg)219 static rt_err_t uart_control(struct rt_serial_device *serial, int cmd, void *arg)
220 {
221     struct hw_uart_device *pdev;
222 
223     RT_ASSERT(serial != RT_NULL);
224 
225     pdev = serial->parent.user_data;
226 
227     switch (cmd)
228     {
229     case RT_DEVICE_CTRL_CLR_INT:
230         /* disable rx irq */
231         ZynqMP_UART_INT_DISABLE(pdev->uart);
232         break;
233 
234     case RT_DEVICE_CTRL_SET_INT:
235         /* enable rx irq */
236         ZynqMP_UART_INT_ENABLE(pdev->uart);
237         rt_hw_interrupt_install(pdev->irqno, rt_hw_uart_isr, serial, serial->parent.parent.name);
238         /* set the interrupt to this cpu */
239         arm_gic_set_cpu(0, pdev->irqno, 1 << rt_cpu_get_smp_id());
240         rt_hw_interrupt_umask(pdev->irqno);
241         break;
242     }
243 
244     return RT_EOK;
245 }
246 
uart_putc(struct rt_serial_device * serial,char c)247 static int uart_putc(struct rt_serial_device *serial, char c)
248 {
249     struct hw_uart_device *dev;
250 
251     RT_ASSERT(serial != RT_NULL);
252     dev = (struct hw_uart_device *)serial->parent.user_data;
253 
254     ZynqMP_UART_SENDCHAR(dev->uart, c);
255 
256     return 1;
257 }
258 
uart_getc(struct rt_serial_device * serial)259 static int uart_getc(struct rt_serial_device *serial)
260 {
261     int ch;
262     struct hw_uart_device *dev;
263 
264     RT_ASSERT(serial != RT_NULL);
265     dev = (struct hw_uart_device *)serial->parent.user_data;
266 
267     ch = -1;
268     ZynqMP_UART_GETCHAR(dev->uart, ch);
269 
270     return ch;
271 }
272 
273 static const struct rt_uart_ops _uart_ops =
274 {
275     uart_configure,
276     uart_control,
277     uart_putc,
278     uart_getc,
279 };
280 
281 /* UART device driver structure */
282 #ifdef BSP_USING_UART0
283 static struct hw_uart_device _uart_device0 =
284 {
285     .uart  = (UART_Registers*)XPAR_PSU_UART_0_BASEADDR,
286     .irqno = XPAR_PSU_UART_0_INTR,
287     .inputClockHz = XPAR_PSU_UART_0_UART_CLK_FREQ_HZ,
288 
289     .rxmio = (rt_uint32_t*)ZynqMP_IOU_SLCR_MIO_PIN(42), /* MIO42 */
290     .txmio = (rt_uint32_t*)ZynqMP_IOU_SLCR_MIO_PIN(43), /* MIO43 */
291 };
292 static struct rt_serial_device _serial0;
293 #endif
294 
rt_hw_uart_init(void)295 int rt_hw_uart_init(void)
296 {
297     struct serial_configure config;
298 
299     config.baud_rate = BAUD_RATE_115200;
300     config.bit_order = BIT_ORDER_LSB;
301     config.data_bits = DATA_BITS_8;
302     config.parity    = PARITY_NONE;
303     config.stop_bits = STOP_BITS_1;
304     config.invert    = NRZ_NORMAL;
305     config.bufsz     = RT_SERIAL_RB_BUFSZ;
306 
307     /* register uart device */
308 #ifdef BSP_USING_UART0
309     _serial0.ops    = &_uart_ops;
310     _serial0.config = config;
311     rt_hw_serial_register(&_serial0, "uart0",
312                           RT_DEVICE_FLAG_RDWR | RT_DEVICE_FLAG_INT_RX,
313                           &_uart_device0);
314 #endif
315 
316     return RT_EOK;
317 }
318 INIT_BOARD_EXPORT(rt_hw_uart_init);
319