xref: /OK3568_Linux_fs/u-boot/drivers/serial/serial_bcm283x_mu.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun /*
2*4882a593Smuzhiyun  * (C) Copyright 2016 Stephen Warren <swarren@wwwdotorg.org>
3*4882a593Smuzhiyun  *
4*4882a593Smuzhiyun  * Derived from pl01x code:
5*4882a593Smuzhiyun  *
6*4882a593Smuzhiyun  * (C) Copyright 2000
7*4882a593Smuzhiyun  * Rob Taylor, Flying Pig Systems. robt@flyingpig.com.
8*4882a593Smuzhiyun  *
9*4882a593Smuzhiyun  * (C) Copyright 2004
10*4882a593Smuzhiyun  * ARM Ltd.
11*4882a593Smuzhiyun  * Philippe Robin, <philippe.robin@arm.com>
12*4882a593Smuzhiyun  *
13*4882a593Smuzhiyun  * SPDX-License-Identifier:	GPL-2.0+
14*4882a593Smuzhiyun  */
15*4882a593Smuzhiyun 
16*4882a593Smuzhiyun /* Simple U-Boot driver for the BCM283x mini UART */
17*4882a593Smuzhiyun 
18*4882a593Smuzhiyun #include <common.h>
19*4882a593Smuzhiyun #include <dm.h>
20*4882a593Smuzhiyun #include <errno.h>
21*4882a593Smuzhiyun #include <watchdog.h>
22*4882a593Smuzhiyun #include <asm/io.h>
23*4882a593Smuzhiyun #include <serial.h>
24*4882a593Smuzhiyun #include <dm/platform_data/serial_bcm283x_mu.h>
25*4882a593Smuzhiyun #include <linux/compiler.h>
26*4882a593Smuzhiyun #include <fdtdec.h>
27*4882a593Smuzhiyun 
28*4882a593Smuzhiyun DECLARE_GLOBAL_DATA_PTR;
29*4882a593Smuzhiyun 
30*4882a593Smuzhiyun struct bcm283x_mu_regs {
31*4882a593Smuzhiyun 	u32 io;
32*4882a593Smuzhiyun 	u32 iir;
33*4882a593Smuzhiyun 	u32 ier;
34*4882a593Smuzhiyun 	u32 lcr;
35*4882a593Smuzhiyun 	u32 mcr;
36*4882a593Smuzhiyun 	u32 lsr;
37*4882a593Smuzhiyun 	u32 msr;
38*4882a593Smuzhiyun 	u32 scratch;
39*4882a593Smuzhiyun 	u32 cntl;
40*4882a593Smuzhiyun 	u32 stat;
41*4882a593Smuzhiyun 	u32 baud;
42*4882a593Smuzhiyun };
43*4882a593Smuzhiyun 
44*4882a593Smuzhiyun #define BCM283X_MU_LCR_DATA_SIZE_8	3
45*4882a593Smuzhiyun 
46*4882a593Smuzhiyun #define BCM283X_MU_LSR_TX_IDLE		BIT(6)
47*4882a593Smuzhiyun /* This actually means not full, but is named not empty in the docs */
48*4882a593Smuzhiyun #define BCM283X_MU_LSR_TX_EMPTY		BIT(5)
49*4882a593Smuzhiyun #define BCM283X_MU_LSR_RX_READY		BIT(0)
50*4882a593Smuzhiyun 
51*4882a593Smuzhiyun struct bcm283x_mu_priv {
52*4882a593Smuzhiyun 	struct bcm283x_mu_regs *regs;
53*4882a593Smuzhiyun };
54*4882a593Smuzhiyun 
bcm283x_mu_serial_setbrg(struct udevice * dev,int baudrate)55*4882a593Smuzhiyun static int bcm283x_mu_serial_setbrg(struct udevice *dev, int baudrate)
56*4882a593Smuzhiyun {
57*4882a593Smuzhiyun 	struct bcm283x_mu_serial_platdata *plat = dev_get_platdata(dev);
58*4882a593Smuzhiyun 	struct bcm283x_mu_priv *priv = dev_get_priv(dev);
59*4882a593Smuzhiyun 	struct bcm283x_mu_regs *regs = priv->regs;
60*4882a593Smuzhiyun 	u32 divider;
61*4882a593Smuzhiyun 
62*4882a593Smuzhiyun 	if (plat->disabled || plat->skip_init)
63*4882a593Smuzhiyun 		return 0;
64*4882a593Smuzhiyun 
65*4882a593Smuzhiyun 	divider = plat->clock / (baudrate * 8);
66*4882a593Smuzhiyun 
67*4882a593Smuzhiyun 	writel(BCM283X_MU_LCR_DATA_SIZE_8, &regs->lcr);
68*4882a593Smuzhiyun 	writel(divider - 1, &regs->baud);
69*4882a593Smuzhiyun 
70*4882a593Smuzhiyun 	return 0;
71*4882a593Smuzhiyun }
72*4882a593Smuzhiyun 
bcm283x_mu_serial_probe(struct udevice * dev)73*4882a593Smuzhiyun static int bcm283x_mu_serial_probe(struct udevice *dev)
74*4882a593Smuzhiyun {
75*4882a593Smuzhiyun 	struct bcm283x_mu_serial_platdata *plat = dev_get_platdata(dev);
76*4882a593Smuzhiyun 	struct bcm283x_mu_priv *priv = dev_get_priv(dev);
77*4882a593Smuzhiyun 
78*4882a593Smuzhiyun 	if (plat->disabled)
79*4882a593Smuzhiyun 		return -ENODEV;
80*4882a593Smuzhiyun 
81*4882a593Smuzhiyun 	priv->regs = (struct bcm283x_mu_regs *)plat->base;
82*4882a593Smuzhiyun 
83*4882a593Smuzhiyun 	return 0;
84*4882a593Smuzhiyun }
85*4882a593Smuzhiyun 
bcm283x_mu_serial_getc(struct udevice * dev)86*4882a593Smuzhiyun static int bcm283x_mu_serial_getc(struct udevice *dev)
87*4882a593Smuzhiyun {
88*4882a593Smuzhiyun 	struct bcm283x_mu_serial_platdata *plat = dev_get_platdata(dev);
89*4882a593Smuzhiyun 	struct bcm283x_mu_priv *priv = dev_get_priv(dev);
90*4882a593Smuzhiyun 	struct bcm283x_mu_regs *regs = priv->regs;
91*4882a593Smuzhiyun 	u32 data;
92*4882a593Smuzhiyun 
93*4882a593Smuzhiyun 	if (plat->disabled)
94*4882a593Smuzhiyun 		return -EAGAIN;
95*4882a593Smuzhiyun 
96*4882a593Smuzhiyun 	/* Wait until there is data in the FIFO */
97*4882a593Smuzhiyun 	if (!(readl(&regs->lsr) & BCM283X_MU_LSR_RX_READY))
98*4882a593Smuzhiyun 		return -EAGAIN;
99*4882a593Smuzhiyun 
100*4882a593Smuzhiyun 	data = readl(&regs->io);
101*4882a593Smuzhiyun 
102*4882a593Smuzhiyun 	return (int)data;
103*4882a593Smuzhiyun }
104*4882a593Smuzhiyun 
bcm283x_mu_serial_putc(struct udevice * dev,const char data)105*4882a593Smuzhiyun static int bcm283x_mu_serial_putc(struct udevice *dev, const char data)
106*4882a593Smuzhiyun {
107*4882a593Smuzhiyun 	struct bcm283x_mu_serial_platdata *plat = dev_get_platdata(dev);
108*4882a593Smuzhiyun 	struct bcm283x_mu_priv *priv = dev_get_priv(dev);
109*4882a593Smuzhiyun 	struct bcm283x_mu_regs *regs = priv->regs;
110*4882a593Smuzhiyun 
111*4882a593Smuzhiyun 	if (plat->disabled)
112*4882a593Smuzhiyun 		return 0;
113*4882a593Smuzhiyun 
114*4882a593Smuzhiyun 	/* Wait until there is space in the FIFO */
115*4882a593Smuzhiyun 	if (!(readl(&regs->lsr) & BCM283X_MU_LSR_TX_EMPTY))
116*4882a593Smuzhiyun 		return -EAGAIN;
117*4882a593Smuzhiyun 
118*4882a593Smuzhiyun 	/* Send the character */
119*4882a593Smuzhiyun 	writel(data, &regs->io);
120*4882a593Smuzhiyun 
121*4882a593Smuzhiyun 	return 0;
122*4882a593Smuzhiyun }
123*4882a593Smuzhiyun 
bcm283x_mu_serial_pending(struct udevice * dev,bool input)124*4882a593Smuzhiyun static int bcm283x_mu_serial_pending(struct udevice *dev, bool input)
125*4882a593Smuzhiyun {
126*4882a593Smuzhiyun 	struct bcm283x_mu_serial_platdata *plat = dev_get_platdata(dev);
127*4882a593Smuzhiyun 	struct bcm283x_mu_priv *priv = dev_get_priv(dev);
128*4882a593Smuzhiyun 	struct bcm283x_mu_regs *regs = priv->regs;
129*4882a593Smuzhiyun 	unsigned int lsr;
130*4882a593Smuzhiyun 
131*4882a593Smuzhiyun 	if (plat->disabled)
132*4882a593Smuzhiyun 		return 0;
133*4882a593Smuzhiyun 
134*4882a593Smuzhiyun 	lsr = readl(&regs->lsr);
135*4882a593Smuzhiyun 
136*4882a593Smuzhiyun 	if (input) {
137*4882a593Smuzhiyun 		WATCHDOG_RESET();
138*4882a593Smuzhiyun 		return (lsr & BCM283X_MU_LSR_RX_READY) ? 1 : 0;
139*4882a593Smuzhiyun 	} else {
140*4882a593Smuzhiyun 		return (lsr & BCM283X_MU_LSR_TX_IDLE) ? 0 : 1;
141*4882a593Smuzhiyun 	}
142*4882a593Smuzhiyun }
143*4882a593Smuzhiyun 
144*4882a593Smuzhiyun static const struct dm_serial_ops bcm283x_mu_serial_ops = {
145*4882a593Smuzhiyun 	.putc = bcm283x_mu_serial_putc,
146*4882a593Smuzhiyun 	.pending = bcm283x_mu_serial_pending,
147*4882a593Smuzhiyun 	.getc = bcm283x_mu_serial_getc,
148*4882a593Smuzhiyun 	.setbrg = bcm283x_mu_serial_setbrg,
149*4882a593Smuzhiyun };
150*4882a593Smuzhiyun 
151*4882a593Smuzhiyun #if CONFIG_IS_ENABLED(OF_CONTROL)
152*4882a593Smuzhiyun static const struct udevice_id bcm283x_mu_serial_id[] = {
153*4882a593Smuzhiyun 	{.compatible = "brcm,bcm2835-aux-uart"},
154*4882a593Smuzhiyun 	{}
155*4882a593Smuzhiyun };
156*4882a593Smuzhiyun 
bcm283x_mu_serial_ofdata_to_platdata(struct udevice * dev)157*4882a593Smuzhiyun static int bcm283x_mu_serial_ofdata_to_platdata(struct udevice *dev)
158*4882a593Smuzhiyun {
159*4882a593Smuzhiyun 	struct bcm283x_mu_serial_platdata *plat = dev_get_platdata(dev);
160*4882a593Smuzhiyun 	fdt_addr_t addr;
161*4882a593Smuzhiyun 
162*4882a593Smuzhiyun 	addr = devfdt_get_addr(dev);
163*4882a593Smuzhiyun 	if (addr == FDT_ADDR_T_NONE)
164*4882a593Smuzhiyun 		return -EINVAL;
165*4882a593Smuzhiyun 
166*4882a593Smuzhiyun 	plat->base = addr;
167*4882a593Smuzhiyun 	plat->clock = fdtdec_get_int(gd->fdt_blob, dev_of_offset(dev), "clock",
168*4882a593Smuzhiyun 				     1);
169*4882a593Smuzhiyun 	plat->skip_init = fdtdec_get_bool(gd->fdt_blob, dev_of_offset(dev),
170*4882a593Smuzhiyun 	                                  "skip-init");
171*4882a593Smuzhiyun 	plat->disabled = false;
172*4882a593Smuzhiyun 	return 0;
173*4882a593Smuzhiyun }
174*4882a593Smuzhiyun #endif
175*4882a593Smuzhiyun 
176*4882a593Smuzhiyun U_BOOT_DRIVER(serial_bcm283x_mu) = {
177*4882a593Smuzhiyun 	.name = "serial_bcm283x_mu",
178*4882a593Smuzhiyun 	.id = UCLASS_SERIAL,
179*4882a593Smuzhiyun 	.of_match = of_match_ptr(bcm283x_mu_serial_id),
180*4882a593Smuzhiyun 	.ofdata_to_platdata = of_match_ptr(bcm283x_mu_serial_ofdata_to_platdata),
181*4882a593Smuzhiyun 	.platdata_auto_alloc_size = sizeof(struct bcm283x_mu_serial_platdata),
182*4882a593Smuzhiyun 	.probe = bcm283x_mu_serial_probe,
183*4882a593Smuzhiyun 	.ops = &bcm283x_mu_serial_ops,
184*4882a593Smuzhiyun 	.flags = DM_FLAG_PRE_RELOC,
185*4882a593Smuzhiyun 	.priv_auto_alloc_size = sizeof(struct bcm283x_mu_priv),
186*4882a593Smuzhiyun };
187