xref: /rk3399_rockchip-uboot/drivers/serial/serial_pic32.c (revision 9e160ee823b44e0a63bc469d42d7d9fcab54b60b)
1*9e160ee8SPaul Thacker /*
2*9e160ee8SPaul Thacker  * (c) 2015 Paul Thacker <paul.thacker@microchip.com>
3*9e160ee8SPaul Thacker  *
4*9e160ee8SPaul Thacker  * SPDX-License-Identifier:	GPL-2.0+
5*9e160ee8SPaul Thacker  *
6*9e160ee8SPaul Thacker  */
7*9e160ee8SPaul Thacker #include <common.h>
8*9e160ee8SPaul Thacker #include <clk.h>
9*9e160ee8SPaul Thacker #include <dm.h>
10*9e160ee8SPaul Thacker #include <serial.h>
11*9e160ee8SPaul Thacker #include <wait_bit.h>
12*9e160ee8SPaul Thacker #include <mach/pic32.h>
13*9e160ee8SPaul Thacker #include <dt-bindings/clock/microchip,clock.h>
14*9e160ee8SPaul Thacker 
15*9e160ee8SPaul Thacker DECLARE_GLOBAL_DATA_PTR;
16*9e160ee8SPaul Thacker 
17*9e160ee8SPaul Thacker /* UART Control Registers */
18*9e160ee8SPaul Thacker #define U_MOD		0x00
19*9e160ee8SPaul Thacker #define U_MODCLR	(U_MOD + _CLR_OFFSET)
20*9e160ee8SPaul Thacker #define U_MODSET	(U_MOD + _SET_OFFSET)
21*9e160ee8SPaul Thacker #define U_STA		0x10
22*9e160ee8SPaul Thacker #define U_STACLR	(U_STA + _CLR_OFFSET)
23*9e160ee8SPaul Thacker #define U_STASET	(U_STA + _SET_OFFSET)
24*9e160ee8SPaul Thacker #define U_TXR		0x20
25*9e160ee8SPaul Thacker #define U_RXR		0x30
26*9e160ee8SPaul Thacker #define U_BRG		0x40
27*9e160ee8SPaul Thacker 
28*9e160ee8SPaul Thacker /* U_MOD bits */
29*9e160ee8SPaul Thacker #define UART_ENABLE		BIT(15)
30*9e160ee8SPaul Thacker 
31*9e160ee8SPaul Thacker /* U_STA bits */
32*9e160ee8SPaul Thacker #define UART_RX_ENABLE		BIT(12)
33*9e160ee8SPaul Thacker #define UART_TX_BRK		BIT(11)
34*9e160ee8SPaul Thacker #define UART_TX_ENABLE		BIT(10)
35*9e160ee8SPaul Thacker #define UART_TX_FULL		BIT(9)
36*9e160ee8SPaul Thacker #define UART_TX_EMPTY		BIT(8)
37*9e160ee8SPaul Thacker #define UART_RX_OVER		BIT(1)
38*9e160ee8SPaul Thacker #define UART_RX_DATA_AVAIL	BIT(0)
39*9e160ee8SPaul Thacker 
40*9e160ee8SPaul Thacker struct pic32_uart_priv {
41*9e160ee8SPaul Thacker 	void __iomem *base;
42*9e160ee8SPaul Thacker 	ulong uartclk;
43*9e160ee8SPaul Thacker };
44*9e160ee8SPaul Thacker 
45*9e160ee8SPaul Thacker /*
46*9e160ee8SPaul Thacker  * Initialize the serial port with the given baudrate.
47*9e160ee8SPaul Thacker  * The settings are always 8 data bits, no parity, 1 stop bit, no start bits.
48*9e160ee8SPaul Thacker  */
49*9e160ee8SPaul Thacker static int pic32_serial_init(void __iomem *base, ulong clk, u32 baudrate)
50*9e160ee8SPaul Thacker {
51*9e160ee8SPaul Thacker 	u32 div = DIV_ROUND_CLOSEST(clk, baudrate * 16);
52*9e160ee8SPaul Thacker 
53*9e160ee8SPaul Thacker 	/* wait for TX FIFO to empty */
54*9e160ee8SPaul Thacker 	wait_for_bit(__func__, base + U_STA, UART_TX_EMPTY,
55*9e160ee8SPaul Thacker 		     true, CONFIG_SYS_HZ, false);
56*9e160ee8SPaul Thacker 
57*9e160ee8SPaul Thacker 	/* send break */
58*9e160ee8SPaul Thacker 	writel(UART_TX_BRK, base + U_STASET);
59*9e160ee8SPaul Thacker 
60*9e160ee8SPaul Thacker 	/* disable and clear mode */
61*9e160ee8SPaul Thacker 	writel(0, base + U_MOD);
62*9e160ee8SPaul Thacker 	writel(0, base + U_STA);
63*9e160ee8SPaul Thacker 
64*9e160ee8SPaul Thacker 	/* set baud rate generator */
65*9e160ee8SPaul Thacker 	writel(div - 1, base + U_BRG);
66*9e160ee8SPaul Thacker 
67*9e160ee8SPaul Thacker 	/* enable the UART for TX and RX */
68*9e160ee8SPaul Thacker 	writel(UART_TX_ENABLE | UART_RX_ENABLE, base + U_STASET);
69*9e160ee8SPaul Thacker 
70*9e160ee8SPaul Thacker 	/* enable the UART */
71*9e160ee8SPaul Thacker 	writel(UART_ENABLE, base + U_MODSET);
72*9e160ee8SPaul Thacker 	return 0;
73*9e160ee8SPaul Thacker }
74*9e160ee8SPaul Thacker 
75*9e160ee8SPaul Thacker /* Check whether any char pending in RX fifo */
76*9e160ee8SPaul Thacker static int pic32_uart_pending_input(void __iomem *base)
77*9e160ee8SPaul Thacker {
78*9e160ee8SPaul Thacker 	/* check if rx buffer overrun error has occurred */
79*9e160ee8SPaul Thacker 	if (readl(base + U_STA) & UART_RX_OVER) {
80*9e160ee8SPaul Thacker 		readl(base + U_RXR);
81*9e160ee8SPaul Thacker 
82*9e160ee8SPaul Thacker 		/* clear overrun error to keep receiving */
83*9e160ee8SPaul Thacker 		writel(UART_RX_OVER, base + U_STACLR);
84*9e160ee8SPaul Thacker 	}
85*9e160ee8SPaul Thacker 
86*9e160ee8SPaul Thacker 	/* In PIC32 there is no way to know number of outstanding
87*9e160ee8SPaul Thacker 	 * chars in rx-fifo. Only it can be known whether there is any.
88*9e160ee8SPaul Thacker 	 */
89*9e160ee8SPaul Thacker 	return readl(base + U_STA) & UART_RX_DATA_AVAIL;
90*9e160ee8SPaul Thacker }
91*9e160ee8SPaul Thacker 
92*9e160ee8SPaul Thacker static int pic32_uart_pending(struct udevice *dev, bool input)
93*9e160ee8SPaul Thacker {
94*9e160ee8SPaul Thacker 	struct pic32_uart_priv *priv = dev_get_priv(dev);
95*9e160ee8SPaul Thacker 
96*9e160ee8SPaul Thacker 	if (input)
97*9e160ee8SPaul Thacker 		return pic32_uart_pending_input(priv->base);
98*9e160ee8SPaul Thacker 
99*9e160ee8SPaul Thacker 	return !(readl(priv->base + U_STA) & UART_TX_EMPTY);
100*9e160ee8SPaul Thacker }
101*9e160ee8SPaul Thacker 
102*9e160ee8SPaul Thacker static int pic32_uart_setbrg(struct udevice *dev, int baudrate)
103*9e160ee8SPaul Thacker {
104*9e160ee8SPaul Thacker 	struct pic32_uart_priv *priv = dev_get_priv(dev);
105*9e160ee8SPaul Thacker 
106*9e160ee8SPaul Thacker 	return pic32_serial_init(priv->base, priv->uartclk, baudrate);
107*9e160ee8SPaul Thacker }
108*9e160ee8SPaul Thacker 
109*9e160ee8SPaul Thacker static int pic32_uart_putc(struct udevice *dev, const char ch)
110*9e160ee8SPaul Thacker {
111*9e160ee8SPaul Thacker 	struct pic32_uart_priv *priv = dev_get_priv(dev);
112*9e160ee8SPaul Thacker 
113*9e160ee8SPaul Thacker 	/* Check if Tx FIFO is full */
114*9e160ee8SPaul Thacker 	if (readl(priv->base + U_STA) & UART_TX_FULL)
115*9e160ee8SPaul Thacker 		return -EAGAIN;
116*9e160ee8SPaul Thacker 
117*9e160ee8SPaul Thacker 	/* pump the char to tx buffer */
118*9e160ee8SPaul Thacker 	writel(ch, priv->base + U_TXR);
119*9e160ee8SPaul Thacker 
120*9e160ee8SPaul Thacker 	return 0;
121*9e160ee8SPaul Thacker }
122*9e160ee8SPaul Thacker 
123*9e160ee8SPaul Thacker static int pic32_uart_getc(struct udevice *dev)
124*9e160ee8SPaul Thacker {
125*9e160ee8SPaul Thacker 	struct pic32_uart_priv *priv = dev_get_priv(dev);
126*9e160ee8SPaul Thacker 
127*9e160ee8SPaul Thacker 	/* return error if RX fifo is empty */
128*9e160ee8SPaul Thacker 	if (!pic32_uart_pending_input(priv->base))
129*9e160ee8SPaul Thacker 		return -EAGAIN;
130*9e160ee8SPaul Thacker 
131*9e160ee8SPaul Thacker 	/* read the character from rx buffer */
132*9e160ee8SPaul Thacker 	return readl(priv->base + U_RXR) & 0xff;
133*9e160ee8SPaul Thacker }
134*9e160ee8SPaul Thacker 
135*9e160ee8SPaul Thacker static int pic32_uart_probe(struct udevice *dev)
136*9e160ee8SPaul Thacker {
137*9e160ee8SPaul Thacker 	struct pic32_uart_priv *priv = dev_get_priv(dev);
138*9e160ee8SPaul Thacker 	struct udevice *clkdev;
139*9e160ee8SPaul Thacker 	fdt_addr_t addr;
140*9e160ee8SPaul Thacker 	fdt_size_t size;
141*9e160ee8SPaul Thacker 	int ret;
142*9e160ee8SPaul Thacker 
143*9e160ee8SPaul Thacker 	/* get address */
144*9e160ee8SPaul Thacker 	addr = fdtdec_get_addr_size(gd->fdt_blob, dev->of_offset, "reg", &size);
145*9e160ee8SPaul Thacker 	if (addr == FDT_ADDR_T_NONE)
146*9e160ee8SPaul Thacker 		return -EINVAL;
147*9e160ee8SPaul Thacker 
148*9e160ee8SPaul Thacker 	priv->base = ioremap(addr, size);
149*9e160ee8SPaul Thacker 
150*9e160ee8SPaul Thacker 	/* get clock rate */
151*9e160ee8SPaul Thacker 	ret = clk_get_by_index(dev, 0, &clkdev);
152*9e160ee8SPaul Thacker 	if (ret < 0)
153*9e160ee8SPaul Thacker 		return ret;
154*9e160ee8SPaul Thacker 	priv->uartclk = clk_get_periph_rate(clkdev, ret);
155*9e160ee8SPaul Thacker 
156*9e160ee8SPaul Thacker 	/* initialize serial */
157*9e160ee8SPaul Thacker 	return pic32_serial_init(priv->base, priv->uartclk, CONFIG_BAUDRATE);
158*9e160ee8SPaul Thacker }
159*9e160ee8SPaul Thacker 
160*9e160ee8SPaul Thacker static const struct dm_serial_ops pic32_uart_ops = {
161*9e160ee8SPaul Thacker 	.putc		= pic32_uart_putc,
162*9e160ee8SPaul Thacker 	.pending	= pic32_uart_pending,
163*9e160ee8SPaul Thacker 	.getc		= pic32_uart_getc,
164*9e160ee8SPaul Thacker 	.setbrg		= pic32_uart_setbrg,
165*9e160ee8SPaul Thacker };
166*9e160ee8SPaul Thacker 
167*9e160ee8SPaul Thacker static const struct udevice_id pic32_uart_ids[] = {
168*9e160ee8SPaul Thacker 	{ .compatible = "microchip,pic32mzda-uart" },
169*9e160ee8SPaul Thacker 	{}
170*9e160ee8SPaul Thacker };
171*9e160ee8SPaul Thacker 
172*9e160ee8SPaul Thacker U_BOOT_DRIVER(pic32_serial) = {
173*9e160ee8SPaul Thacker 	.name		= "pic32-uart",
174*9e160ee8SPaul Thacker 	.id		= UCLASS_SERIAL,
175*9e160ee8SPaul Thacker 	.of_match	= pic32_uart_ids,
176*9e160ee8SPaul Thacker 	.probe		= pic32_uart_probe,
177*9e160ee8SPaul Thacker 	.ops		= &pic32_uart_ops,
178*9e160ee8SPaul Thacker 	.flags		= DM_FLAG_PRE_RELOC,
179*9e160ee8SPaul Thacker 	.priv_auto_alloc_size = sizeof(struct pic32_uart_priv),
180*9e160ee8SPaul Thacker };
181*9e160ee8SPaul Thacker 
182*9e160ee8SPaul Thacker #ifdef CONFIG_DEBUG_UART_PIC32
183*9e160ee8SPaul Thacker #include <debug_uart.h>
184*9e160ee8SPaul Thacker 
185*9e160ee8SPaul Thacker static inline void _debug_uart_init(void)
186*9e160ee8SPaul Thacker {
187*9e160ee8SPaul Thacker 	void __iomem *base = (void __iomem *)CONFIG_DEBUG_UART_BASE;
188*9e160ee8SPaul Thacker 
189*9e160ee8SPaul Thacker 	pic32_serial_init(base, CONFIG_DEBUG_UART_CLOCK, CONFIG_BAUDRATE);
190*9e160ee8SPaul Thacker }
191*9e160ee8SPaul Thacker 
192*9e160ee8SPaul Thacker static inline void _debug_uart_putc(int ch)
193*9e160ee8SPaul Thacker {
194*9e160ee8SPaul Thacker 	writel(ch, CONFIG_DEBUG_UART_BASE + U_TXR);
195*9e160ee8SPaul Thacker }
196*9e160ee8SPaul Thacker 
197*9e160ee8SPaul Thacker DEBUG_UART_FUNCS
198*9e160ee8SPaul Thacker #endif
199