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