xref: /nrf52832-nimble/rt-thread/libcpu/ppc/ppc405/serial.c (revision 104654410c56c573564690304ae786df310c91fc)
1 #include <rthw.h>
2 #include <rtthread.h>
3 
4 #include "io.h"
5 #include <asm/ppc4xx-intvec.h>
6 
7 #define UART0_BASE      0xef600300
8 #define UART1_BASE      0xef600400
9 #define UCR0_MASK       0x0000007f
10 #define UCR1_MASK       0x00007f00
11 #define UCR0_UDIV_POS   0
12 #define UCR1_UDIV_POS   8
13 #define UDIV_MAX        127
14 
15 #define UART_RBR		0x00
16 #define UART_THR		0x00
17 #define UART_IER		0x01
18 #define UART_IIR		0x02
19 #define UART_FCR		0x02
20 #define UART_LCR		0x03
21 #define UART_MCR		0x04
22 #define UART_LSR		0x05
23 #define UART_MSR		0x06
24 #define UART_SCR		0x07
25 #define UART_DLL		0x00
26 #define UART_DLM		0x01
27 
28 /*-----------------------------------------------------------------------------+
29   | Line Status Register.
30   +-----------------------------------------------------------------------------*/
31 #define asyncLSRDataReady1            0x01
32 #define asyncLSROverrunError1         0x02
33 #define asyncLSRParityError1          0x04
34 #define asyncLSRFramingError1         0x08
35 #define asyncLSRBreakInterrupt1       0x10
36 #define asyncLSRTxHoldEmpty1          0x20
37 #define asyncLSRTxShiftEmpty1         0x40
38 #define asyncLSRRxFifoError1          0x80
39 
40 /* PPC405 serial device */
41 struct rt_ppc405_serial
42 {
43 	/* inherit from device */
44 	struct rt_device parent;
45 
46 	rt_uint32_t hw_base;
47 	rt_uint32_t irqno;
48 	rt_uint32_t baudrate;
49 
50 	/* reception field */
51 	rt_uint16_t save_index, read_index;
52 	rt_uint8_t  rx_buffer[RT_UART_RX_BUFFER_SIZE];
53 };
54 struct rt_ppc405_serial ppc405_serial;
55 
56 /* serial character device */
rt_serial_init(rt_device_t dev)57 static rt_err_t rt_serial_init (rt_device_t dev)
58 {
59 	return RT_EOK;
60 }
61 
rt_serial_open(rt_device_t dev,rt_uint16_t oflag)62 static rt_err_t rt_serial_open(rt_device_t dev, rt_uint16_t oflag)
63 {
64 	struct rt_ppc405_serial* device;
65 	device = (struct rt_ppc405_serial*) dev;
66 
67 	RT_ASSERT(device != RT_NULL);
68 	if (dev->flag & RT_DEVICE_FLAG_INT_RX)
69 	{
70 		/* Enable "RX Data Available" Interrupt on UART */
71 		out_8((rt_uint8_t*)device->hw_base + UART_IER, 0x01);
72 		/* Setup UART FIFO: RX trigger level: 1 byte, Enable FIFO */
73 		out_8((rt_uint8_t*)device->hw_base + UART_FCR, 1);
74 
75 	    /* init UART rx interrupt */
76 	    rt_hw_interrupt_unmask(device->irqno);
77 	}
78 
79 	return RT_EOK;
80 }
81 
rt_serial_close(rt_device_t dev)82 static rt_err_t rt_serial_close(rt_device_t dev)
83 {
84 	struct rt_ppc405_serial* device;
85 	device = (struct rt_ppc405_serial*) dev;
86 
87 	RT_ASSERT(device != RT_NULL);
88 	if (dev->flag & RT_DEVICE_FLAG_INT_RX)
89 	{
90 		/* mask UART rx interrupt */
91 	    rt_hw_interrupt_mask(device->irqno);
92 	}
93 
94 	return RT_EOK;
95 }
96 
rt_serial_control(rt_device_t dev,int cmd,void * args)97 static rt_err_t rt_serial_control(rt_device_t dev, int cmd, void *args)
98 {
99 	return RT_EOK;
100 }
101 
rt_serial_read(rt_device_t dev,rt_off_t pos,void * buffer,rt_size_t size)102 static rt_size_t rt_serial_read(rt_device_t dev, rt_off_t pos, void* buffer, rt_size_t size)
103 {
104 	rt_uint8_t* ptr;
105 	struct rt_ppc405_serial* device;
106 
107 	device = (struct rt_ppc405_serial*) dev;
108 	RT_ASSERT(device != RT_NULL);
109 
110 	/* point to buffer */
111 	ptr = (rt_uint8_t*) buffer;
112 
113 	if (dev->flag & RT_DEVICE_FLAG_INT_RX)
114 	{
115 		while (size)
116 		{
117 			/* interrupt receive */
118 			rt_base_t level;
119 
120 			/* disable interrupt */
121 			level = rt_hw_interrupt_disable();
122 			if (device->read_index != device->save_index)
123 			{
124 				*ptr = device->rx_buffer[device->read_index];
125 
126 				device->read_index ++;
127 				if (device->read_index >= RT_UART_RX_BUFFER_SIZE)
128 					device->read_index = 0;
129 			}
130 			else
131 			{
132 				/* no data in rx buffer */
133 
134 				/* enable interrupt */
135 				rt_hw_interrupt_enable(level);
136 				break;
137 			}
138 
139 			/* enable interrupt */
140 			rt_hw_interrupt_enable(level);
141 
142 			ptr ++; size --;
143 		}
144 
145 		return (rt_uint32_t)ptr - (rt_uint32_t)buffer;
146 	}
147 	else if (dev->flag & RT_DEVICE_FLAG_DMA_RX)
148 	{
149 		/* not support right now */
150 		RT_ASSERT(0);
151 	}
152 
153 	/* polling mode */
154 	RT_ASSERT(0);
155 
156 	return (rt_size_t)ptr - (rt_size_t)buffer;
157 }
158 
rt_serial_write(rt_device_t dev,rt_off_t pos,const void * buffer,rt_size_t size)159 static rt_size_t rt_serial_write(rt_device_t dev, rt_off_t pos, const void* buffer, rt_size_t size)
160 {
161 	char *ptr;
162 	struct rt_ppc405_serial* device;
163 
164 	device = (struct rt_ppc405_serial*) dev;
165 	RT_ASSERT(device != RT_NULL);
166 
167 	if (dev->flag & RT_DEVICE_FLAG_INT_TX)
168 	{
169 		/* not support */
170 		RT_ASSERT(0);
171 	}
172 	else if (dev->flag & RT_DEVICE_FLAG_DMA_TX)
173 	{
174 		/* not support */
175 		RT_ASSERT(0);
176 	}
177 
178 	/* polling write */
179 	ptr = (char *)buffer;
180 
181 	if (dev->flag & RT_DEVICE_FLAG_STREAM)
182 	{
183 		/* stream mode */
184 		while (size)
185 		{
186 			if (*ptr == '\n')
187 			{
188 				while ((in_8((rt_uint8_t*)device->hw_base + UART_LSR) & 0x20) != 0x20);
189 				out_8((rt_uint8_t*)device->hw_base + UART_THR, '\r');
190 			}
191 
192 			while ((in_8((rt_uint8_t*)device->hw_base + UART_LSR) & 0x20) != 0x20);
193 			out_8((rt_uint8_t*)device->hw_base + UART_THR, *ptr);
194 
195 			ptr ++;
196 			size --;
197 		}
198 	}
199 	else
200 	{
201 		while (size)
202 		{
203 			while ((in_8((rt_uint8_t*)device->hw_base + UART_LSR) & 0x20) != 0x20);
204 			out_8((rt_uint8_t*)device->hw_base + UART_THR, *ptr);
205 
206 			ptr ++;
207 			size --;
208 		}
209 	}
210 
211 	return (rt_size_t) ptr - (rt_size_t) buffer;
212 }
213 
rt_serial_set_baudrate(struct rt_ppc405_serial * device)214 void rt_serial_set_baudrate(struct rt_ppc405_serial* device)
215 {
216 	rt_uint32_t bdiv;
217 
218 	bdiv = 115200;
219 	out_8((rt_uint8_t *)device->hw_base + UART_DLL, bdiv);		/* set baudrate divisor */
220 	out_8((rt_uint8_t *)device->hw_base + UART_DLM, bdiv >> 8); /* set baudrate divisor */
221 }
222 
rt_serial_isr(int irqno,void * param)223 void rt_serial_isr(int irqno, void* param)
224 {
225 	unsigned char status;
226 	struct rt_ppc405_serial *device;
227 
228 	device = (struct rt_ppc405_serial*) param;
229 	status = in_8((rt_uint8_t *)device->hw_base + UART_LSR);
230 
231 	if (status & 0x01)
232 	{
233 		rt_base_t level;
234 
235 		while (status & 0x01)
236 		{
237 			/* disable interrupt */
238 			level = rt_hw_interrupt_disable();
239 
240 			/* read character */
241 			device->rx_buffer[device->save_index] = (0xff & (int) in_8((rt_uint8_t *)device->hw_base));
242 			device->save_index ++;
243 			if (device->save_index >= RT_UART_RX_BUFFER_SIZE)
244 				device->save_index = 0;
245 
246 			/* if the next position is read index, discard this 'read char' */
247 			if (device->save_index == device->read_index)
248 			{
249 				device->read_index ++;
250 				if (device->read_index >= RT_UART_RX_BUFFER_SIZE)
251 					device->read_index = 0;
252 			}
253 
254 			/* enable interrupt */
255 			rt_hw_interrupt_enable(level);
256 
257 			/* check error */
258 			if ((status & ( asyncLSRFramingError1 |
259 					asyncLSROverrunError1 |
260 					asyncLSRParityError1  |
261 					asyncLSRBreakInterrupt1 )) != 0)
262 			{
263 				out_8((rt_uint8_t *)device->hw_base + UART_LSR,
264 					  asyncLSRFramingError1 |
265 					  asyncLSROverrunError1 |
266 					  asyncLSRParityError1  |
267 					  asyncLSRBreakInterrupt1);
268 			}
269 
270 			status = in_8((rt_uint8_t *)device->hw_base + UART_LSR);
271 		}
272 
273 		/* invoke callback */
274 		if(device->parent.rx_indicate != RT_NULL)
275 		{
276 		  device->parent.rx_indicate(&device->parent, 1);
277 		}
278 	}
279 }
280 
rt_hw_serial_init(void)281 void rt_hw_serial_init(void)
282 {
283 	volatile rt_uint8_t val;
284 	struct rt_ppc405_serial* device;
285 
286 	device = (struct rt_ppc405_serial*) &ppc405_serial;
287 	device->parent.type = RT_Device_Class_Char;
288 
289 	device->hw_base = UART0_BASE;
290 	device->baudrate = 115200;
291 	device->irqno = VECNUM_U0;
292 	rt_hw_interrupt_install(device->irqno, rt_serial_isr, device, "serial"); /* install isr */
293 
294 	rt_memset(device->rx_buffer, 0, sizeof(device->rx_buffer));
295 	device->read_index = device->save_index = 0;
296 
297 	out_8((rt_uint8_t *)device->hw_base + UART_LCR, 0x80);	/* set DLAB bit */
298 	/* setup baudrate */
299 	rt_serial_set_baudrate(device);
300 	out_8((rt_uint8_t *)device->hw_base + UART_LCR, 0x03);	/* clear DLAB; set 8 bits, no parity */
301 	out_8((rt_uint8_t *)device->hw_base + UART_FCR, 0x00);	/* disable FIFO */
302 	out_8((rt_uint8_t *)device->hw_base + UART_MCR, 0x00);	/* no modem control DTR RTS */
303 	val = in_8((rt_uint8_t *)device->hw_base + UART_LSR);	/* clear line status */
304 	val = in_8((rt_uint8_t *)device->hw_base + UART_RBR);	/* read receive buffer */
305 	out_8((rt_uint8_t *)device->hw_base + UART_SCR, 0x00);	/* set scratchpad */
306 	out_8((rt_uint8_t *)device->hw_base + UART_IER, 0x00);	/* set interrupt enable reg */
307 
308 	device->parent.type     = RT_Device_Class_Char;
309 	device->parent.init 	= rt_serial_init;
310 	device->parent.open 	= rt_serial_open;
311 	device->parent.close    = rt_serial_close;
312 	device->parent.read 	= rt_serial_read;
313 	device->parent.write    = rt_serial_write;
314 	device->parent.control  = rt_serial_control;
315 	device->parent.user_data  = RT_NULL;
316 
317 	rt_device_register(&device->parent,
318 		"uart1", RT_DEVICE_FLAG_RDWR | RT_DEVICE_FLAG_INT_RX | RT_DEVICE_FLAG_STREAM);
319 }
320