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-04-09     Jonne        Code refactoring for new bsp
9  */
10 
11 #include <stddef.h>
12 #include <rthw.h>
13 #include <rtdevice.h>
14 #include <board.h>
15 
16 #define ULCON_OFS               0x00
17 #define UCON_OFS                0x04
18 #define UFCON_OFS               0x08
19 #define UMCON_OFS               0x0c
20 #define UTRSTAT_OFS             0x10
21 #define UERSTAT_OFS             0x14
22 #define UFSTAT_OFS              0x18
23 #define UMSTAT_OFS              0x1c
24 #define UTXH_OFS                0x20
25 #define URXH_OFS                0x24
26 #define UBRDIV_OFS              0x28
27 
28 #define readl(addr)             (*(volatile unsigned long *)(addr))
29 #define writel(addr, value)     (*(volatile unsigned long *)(addr) = value)
30 
31 #define PCLK_HZ                 50000000
32 
33 struct hw_uart_device
34 {
35     rt_uint32_t hw_base;
36     rt_uint32_t irqno;
37 };
38 
s3c2440_serial_configure(struct rt_serial_device * serial,struct serial_configure * cfg)39 static rt_err_t s3c2440_serial_configure(struct rt_serial_device *serial, struct serial_configure *cfg)
40 {
41     struct hw_uart_device *uart = serial->parent.user_data;
42 
43     writel(uart->hw_base + UBRDIV_OFS, PCLK_HZ / (cfg->baud_rate * 16));
44 
45     writel(uart->hw_base + ULCON_OFS, 0x03);// 8bit data, 1bit stop, No parity
46     writel(uart->hw_base + UCON_OFS, 0x05);
47     writel(uart->hw_base + UFCON_OFS, 0x00);
48     writel(uart->hw_base + UMCON_OFS, 0x00);
49 
50     return RT_EOK;
51 }
52 
s3c2440_serial_control(struct rt_serial_device * serial,int cmd,void * arg)53 static rt_err_t s3c2440_serial_control(struct rt_serial_device *serial, int cmd, void *arg)
54 {
55     struct hw_uart_device *uart;
56     int mask;
57 
58     RT_ASSERT(serial != RT_NULL);
59     uart = (struct hw_uart_device *)serial->parent.user_data;
60 
61     if (uart->irqno == INTUART0)
62     {
63         mask = BIT_SUB_RXD0;
64     }
65     else if (uart->irqno == INTUART1)
66     {
67         mask = BIT_SUB_RXD1;
68     }
69     else
70     {
71         mask = BIT_SUB_RXD2;
72     }
73 
74     switch (cmd)
75     {
76     case RT_DEVICE_CTRL_CLR_INT:
77         /* disable rx irq */
78         INTSUBMSK |= mask;
79 
80         break;
81 
82     case RT_DEVICE_CTRL_SET_INT:
83         /* enable rx irq */
84         INTSUBMSK &= ~mask;
85         break;
86     }
87 
88     return RT_EOK;
89 }
s3c2440_putc(struct rt_serial_device * serial,char c)90 static int s3c2440_putc(struct rt_serial_device *serial, char c)
91 {
92     struct hw_uart_device *uart = serial->parent.user_data;
93 
94     while (!(readl(uart->hw_base + UTRSTAT_OFS) & (1 << 2)))
95     {
96     }
97 
98     writel(uart->hw_base + UTXH_OFS, c);
99 
100     return 0;
101 
102 
103 }
s3c2440_getc(struct rt_serial_device * serial)104 static int s3c2440_getc(struct rt_serial_device *serial)
105 {
106     struct hw_uart_device *uart = serial->parent.user_data;
107     int ch = -1;
108 
109     if (readl(uart->hw_base + UTRSTAT_OFS) & (1 << 0))
110     {
111         ch = readl(uart->hw_base + URXH_OFS) & 0x000000FF;
112     }
113 
114     return ch;
115 }
116 
rt_hw_uart_isr(int irqno,void * param)117 static void rt_hw_uart_isr(int irqno, void *param)
118 {
119     struct rt_serial_device *serial = (struct rt_serial_device *)param;
120 
121     rt_hw_serial_isr(serial, RT_SERIAL_EVENT_RX_IND);
122 
123     /*clear SUBSRCPND*/
124     if (irqno == INTUART0)
125     {
126         SUBSRCPND = BIT_SUB_RXD0;
127     }
128     else if (irqno == INTUART1)
129     {
130         SUBSRCPND = BIT_SUB_RXD1;
131     }
132     else
133     {
134         SUBSRCPND = BIT_SUB_RXD2;
135     }
136 }
137 
138 static struct rt_uart_ops s3c2440_uart_ops =
139 {
140     .configure = s3c2440_serial_configure,
141     .control = s3c2440_serial_control,
142     .putc = s3c2440_putc,
143     .getc = s3c2440_getc
144 };
145 
146 
147 static struct rt_serial_device _serial0 =
148 {
149     .ops = &s3c2440_uart_ops,
150     .config = RT_SERIAL_CONFIG_DEFAULT,
151     .serial_rx = NULL,
152     .serial_tx = NULL
153 };
154 static struct hw_uart_device _hwserial0 =
155 {
156     .hw_base = 0x50000000,
157     .irqno = INTUART0
158 };
159 
160 static struct rt_serial_device _serial1 =
161 {
162     .ops = &s3c2440_uart_ops,
163     .config = RT_SERIAL_CONFIG_DEFAULT,
164     .serial_rx = NULL,
165     .serial_tx = NULL
166 };
167 static struct hw_uart_device _hwserial1 =
168 {
169     .hw_base = 0x50004000,
170     .irqno = INTUART1
171 };
172 
173 static struct rt_serial_device _serial2 =
174 {
175     .ops = &s3c2440_uart_ops,
176     .config = RT_SERIAL_CONFIG_DEFAULT,
177     .serial_rx = NULL,
178     .serial_tx = NULL
179 };
180 static struct hw_uart_device _hwserial2 =
181 {
182     .hw_base = 0x50008000,
183     .irqno = INTUART2
184 };
185 
186 
rt_hw_uart_init(void)187 int rt_hw_uart_init(void)
188 {
189     /* UART0  UART1 UART2 port configure */
190     GPHCON |= 0xAAAA;
191     /* PULLUP is disable */
192     GPHUP |= 0xFFF;
193 
194     /* register UART0 device */
195     rt_hw_serial_register(&_serial0, "uart0", RT_DEVICE_FLAG_RDWR | RT_DEVICE_FLAG_INT_RX, &_hwserial0);
196     rt_hw_interrupt_install(_hwserial0.irqno, rt_hw_uart_isr, &_serial0, "uart0");
197     rt_hw_interrupt_umask(INTUART0);
198 
199     /* register UART1 device */
200     rt_hw_serial_register(&_serial1, "uart1", RT_DEVICE_FLAG_RDWR | RT_DEVICE_FLAG_INT_RX, &_hwserial1);
201     rt_hw_interrupt_install(_hwserial1.irqno, rt_hw_uart_isr, &_serial1, "uart1");
202     rt_hw_interrupt_umask(INTUART1);
203 
204     /* register UART2 device */
205     rt_hw_serial_register(&_serial2, "uart2", RT_DEVICE_FLAG_RDWR | RT_DEVICE_FLAG_INT_RX, &_hwserial2);
206     rt_hw_interrupt_install(_hwserial2.irqno, rt_hw_uart_isr, &_serial2, "uart2");
207     rt_hw_interrupt_umask(INTUART2);
208 
209     return RT_EOK;
210 }
211 INIT_BOARD_EXPORT(rt_hw_uart_init);
212 
213