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