1 | // SPDX-License-Identifier: GPL-2.0-or-later |
2 | /* |
3 | * Embedded Planet EP8248E support |
4 | * |
5 | * Copyright 2007 Freescale Semiconductor, Inc. |
6 | * Author: Scott Wood <scottwood@freescale.com> |
7 | */ |
8 | |
9 | #include <linux/init.h> |
10 | #include <linux/interrupt.h> |
11 | #include <linux/fsl_devices.h> |
12 | #include <linux/mdio-bitbang.h> |
13 | #include <linux/of_mdio.h> |
14 | #include <linux/slab.h> |
15 | #include <linux/of_platform.h> |
16 | #include <linux/platform_device.h> |
17 | |
18 | #include <asm/io.h> |
19 | #include <asm/cpm2.h> |
20 | #include <asm/udbg.h> |
21 | #include <asm/machdep.h> |
22 | #include <asm/time.h> |
23 | |
24 | #include <sysdev/fsl_soc.h> |
25 | #include <sysdev/cpm2_pic.h> |
26 | |
27 | #include "pq2.h" |
28 | |
29 | static u8 __iomem *ep8248e_bcsr; |
30 | static struct device_node *ep8248e_bcsr_node; |
31 | |
32 | #define BCSR7_SCC2_ENABLE 0x10 |
33 | |
34 | #define BCSR8_PHY1_ENABLE 0x80 |
35 | #define BCSR8_PHY1_POWER 0x40 |
36 | #define BCSR8_PHY2_ENABLE 0x20 |
37 | #define BCSR8_PHY2_POWER 0x10 |
38 | #define BCSR8_MDIO_READ 0x04 |
39 | #define BCSR8_MDIO_CLOCK 0x02 |
40 | #define BCSR8_MDIO_DATA 0x01 |
41 | |
42 | #define BCSR9_USB_ENABLE 0x80 |
43 | #define BCSR9_USB_POWER 0x40 |
44 | #define BCSR9_USB_HOST 0x20 |
45 | #define BCSR9_USB_FULL_SPEED_TARGET 0x10 |
46 | |
47 | static void __init ep8248e_pic_init(void) |
48 | { |
49 | struct device_node *np = of_find_compatible_node(NULL, NULL, compat: "fsl,pq2-pic" ); |
50 | if (!np) { |
51 | printk(KERN_ERR "PIC init: can not find cpm-pic node\n" ); |
52 | return; |
53 | } |
54 | |
55 | cpm2_pic_init(np); |
56 | of_node_put(node: np); |
57 | } |
58 | |
59 | static void ep8248e_set_mdc(struct mdiobb_ctrl *ctrl, int level) |
60 | { |
61 | if (level) |
62 | setbits8(&ep8248e_bcsr[8], BCSR8_MDIO_CLOCK); |
63 | else |
64 | clrbits8(&ep8248e_bcsr[8], BCSR8_MDIO_CLOCK); |
65 | |
66 | /* Read back to flush the write. */ |
67 | in_8(&ep8248e_bcsr[8]); |
68 | } |
69 | |
70 | static void ep8248e_set_mdio_dir(struct mdiobb_ctrl *ctrl, int output) |
71 | { |
72 | if (output) |
73 | clrbits8(&ep8248e_bcsr[8], BCSR8_MDIO_READ); |
74 | else |
75 | setbits8(&ep8248e_bcsr[8], BCSR8_MDIO_READ); |
76 | |
77 | /* Read back to flush the write. */ |
78 | in_8(&ep8248e_bcsr[8]); |
79 | } |
80 | |
81 | static void ep8248e_set_mdio_data(struct mdiobb_ctrl *ctrl, int data) |
82 | { |
83 | if (data) |
84 | setbits8(&ep8248e_bcsr[8], BCSR8_MDIO_DATA); |
85 | else |
86 | clrbits8(&ep8248e_bcsr[8], BCSR8_MDIO_DATA); |
87 | |
88 | /* Read back to flush the write. */ |
89 | in_8(&ep8248e_bcsr[8]); |
90 | } |
91 | |
92 | static int ep8248e_get_mdio_data(struct mdiobb_ctrl *ctrl) |
93 | { |
94 | return in_8(&ep8248e_bcsr[8]) & BCSR8_MDIO_DATA; |
95 | } |
96 | |
97 | static const struct mdiobb_ops ep8248e_mdio_ops = { |
98 | .set_mdc = ep8248e_set_mdc, |
99 | .set_mdio_dir = ep8248e_set_mdio_dir, |
100 | .set_mdio_data = ep8248e_set_mdio_data, |
101 | .get_mdio_data = ep8248e_get_mdio_data, |
102 | .owner = THIS_MODULE, |
103 | }; |
104 | |
105 | static struct mdiobb_ctrl ep8248e_mdio_ctrl = { |
106 | .ops = &ep8248e_mdio_ops, |
107 | }; |
108 | |
109 | static int ep8248e_mdio_probe(struct platform_device *ofdev) |
110 | { |
111 | struct mii_bus *bus; |
112 | struct resource res; |
113 | struct device_node *node; |
114 | int ret; |
115 | |
116 | node = of_get_parent(node: ofdev->dev.of_node); |
117 | of_node_put(node); |
118 | if (node != ep8248e_bcsr_node) |
119 | return -ENODEV; |
120 | |
121 | ret = of_address_to_resource(ofdev->dev.of_node, 0, &res); |
122 | if (ret) |
123 | return ret; |
124 | |
125 | bus = alloc_mdio_bitbang(ctrl: &ep8248e_mdio_ctrl); |
126 | if (!bus) |
127 | return -ENOMEM; |
128 | |
129 | bus->name = "ep8248e-mdio-bitbang" ; |
130 | bus->parent = &ofdev->dev; |
131 | snprintf(buf: bus->id, MII_BUS_ID_SIZE, fmt: "%x" , res.start); |
132 | |
133 | ret = of_mdiobus_register(mdio: bus, np: ofdev->dev.of_node); |
134 | if (ret) |
135 | goto err_free_bus; |
136 | |
137 | return 0; |
138 | err_free_bus: |
139 | free_mdio_bitbang(bus); |
140 | return ret; |
141 | } |
142 | |
143 | static const struct of_device_id ep8248e_mdio_match[] = { |
144 | { |
145 | .compatible = "fsl,ep8248e-mdio-bitbang" , |
146 | }, |
147 | {}, |
148 | }; |
149 | |
150 | static struct platform_driver ep8248e_mdio_driver = { |
151 | .driver = { |
152 | .name = "ep8248e-mdio-bitbang" , |
153 | .of_match_table = ep8248e_mdio_match, |
154 | .suppress_bind_attrs = true, |
155 | }, |
156 | .probe = ep8248e_mdio_probe, |
157 | }; |
158 | |
159 | struct cpm_pin { |
160 | int port, pin, flags; |
161 | }; |
162 | |
163 | static __initdata struct cpm_pin ep8248e_pins[] = { |
164 | /* SMC1 */ |
165 | {2, 4, CPM_PIN_INPUT | CPM_PIN_PRIMARY}, |
166 | {2, 5, CPM_PIN_OUTPUT | CPM_PIN_PRIMARY}, |
167 | |
168 | /* SCC1 */ |
169 | {2, 14, CPM_PIN_INPUT | CPM_PIN_PRIMARY}, |
170 | {2, 15, CPM_PIN_INPUT | CPM_PIN_PRIMARY}, |
171 | {3, 29, CPM_PIN_OUTPUT | CPM_PIN_PRIMARY}, |
172 | {3, 30, CPM_PIN_OUTPUT | CPM_PIN_SECONDARY}, |
173 | {3, 31, CPM_PIN_INPUT | CPM_PIN_PRIMARY}, |
174 | |
175 | /* FCC1 */ |
176 | {0, 14, CPM_PIN_INPUT | CPM_PIN_PRIMARY}, |
177 | {0, 15, CPM_PIN_INPUT | CPM_PIN_PRIMARY}, |
178 | {0, 16, CPM_PIN_INPUT | CPM_PIN_PRIMARY}, |
179 | {0, 17, CPM_PIN_INPUT | CPM_PIN_PRIMARY}, |
180 | {0, 18, CPM_PIN_OUTPUT | CPM_PIN_PRIMARY}, |
181 | {0, 19, CPM_PIN_OUTPUT | CPM_PIN_PRIMARY}, |
182 | {0, 20, CPM_PIN_OUTPUT | CPM_PIN_PRIMARY}, |
183 | {0, 21, CPM_PIN_OUTPUT | CPM_PIN_PRIMARY}, |
184 | {0, 26, CPM_PIN_INPUT | CPM_PIN_SECONDARY}, |
185 | {0, 27, CPM_PIN_INPUT | CPM_PIN_SECONDARY}, |
186 | {0, 28, CPM_PIN_OUTPUT | CPM_PIN_SECONDARY}, |
187 | {0, 29, CPM_PIN_OUTPUT | CPM_PIN_SECONDARY}, |
188 | {0, 30, CPM_PIN_INPUT | CPM_PIN_SECONDARY}, |
189 | {0, 31, CPM_PIN_INPUT | CPM_PIN_SECONDARY}, |
190 | {2, 21, CPM_PIN_INPUT | CPM_PIN_PRIMARY}, |
191 | {2, 22, CPM_PIN_INPUT | CPM_PIN_PRIMARY}, |
192 | |
193 | /* FCC2 */ |
194 | {1, 18, CPM_PIN_INPUT | CPM_PIN_PRIMARY}, |
195 | {1, 19, CPM_PIN_INPUT | CPM_PIN_PRIMARY}, |
196 | {1, 20, CPM_PIN_INPUT | CPM_PIN_PRIMARY}, |
197 | {1, 21, CPM_PIN_INPUT | CPM_PIN_PRIMARY}, |
198 | {1, 22, CPM_PIN_OUTPUT | CPM_PIN_PRIMARY}, |
199 | {1, 23, CPM_PIN_OUTPUT | CPM_PIN_PRIMARY}, |
200 | {1, 24, CPM_PIN_OUTPUT | CPM_PIN_PRIMARY}, |
201 | {1, 25, CPM_PIN_OUTPUT | CPM_PIN_PRIMARY}, |
202 | {1, 26, CPM_PIN_INPUT | CPM_PIN_PRIMARY}, |
203 | {1, 27, CPM_PIN_INPUT | CPM_PIN_PRIMARY}, |
204 | {1, 28, CPM_PIN_INPUT | CPM_PIN_PRIMARY}, |
205 | {1, 29, CPM_PIN_OUTPUT | CPM_PIN_SECONDARY}, |
206 | {1, 30, CPM_PIN_INPUT | CPM_PIN_PRIMARY}, |
207 | {1, 31, CPM_PIN_OUTPUT | CPM_PIN_PRIMARY}, |
208 | {2, 18, CPM_PIN_INPUT | CPM_PIN_PRIMARY}, |
209 | {2, 19, CPM_PIN_INPUT | CPM_PIN_PRIMARY}, |
210 | |
211 | /* I2C */ |
212 | {4, 14, CPM_PIN_INPUT | CPM_PIN_SECONDARY}, |
213 | {4, 15, CPM_PIN_INPUT | CPM_PIN_SECONDARY}, |
214 | |
215 | /* USB */ |
216 | {2, 10, CPM_PIN_INPUT | CPM_PIN_PRIMARY}, |
217 | {2, 11, CPM_PIN_INPUT | CPM_PIN_PRIMARY}, |
218 | {2, 20, CPM_PIN_OUTPUT | CPM_PIN_PRIMARY}, |
219 | {2, 24, CPM_PIN_INPUT | CPM_PIN_PRIMARY}, |
220 | {3, 23, CPM_PIN_OUTPUT | CPM_PIN_PRIMARY}, |
221 | {3, 24, CPM_PIN_OUTPUT | CPM_PIN_PRIMARY}, |
222 | {3, 25, CPM_PIN_INPUT | CPM_PIN_PRIMARY}, |
223 | }; |
224 | |
225 | static void __init init_ioports(void) |
226 | { |
227 | int i; |
228 | |
229 | for (i = 0; i < ARRAY_SIZE(ep8248e_pins); i++) { |
230 | const struct cpm_pin *pin = &ep8248e_pins[i]; |
231 | cpm2_set_pin(pin->port, pin->pin, pin->flags); |
232 | } |
233 | |
234 | cpm2_smc_clk_setup(CPM_CLK_SMC1, CPM_BRG7); |
235 | cpm2_clk_setup(CPM_CLK_SCC1, CPM_BRG1, CPM_CLK_RX); |
236 | cpm2_clk_setup(CPM_CLK_SCC1, CPM_BRG1, CPM_CLK_TX); |
237 | cpm2_clk_setup(CPM_CLK_SCC3, CPM_CLK8, CPM_CLK_TX); /* USB */ |
238 | cpm2_clk_setup(CPM_CLK_FCC1, CPM_CLK11, CPM_CLK_RX); |
239 | cpm2_clk_setup(CPM_CLK_FCC1, CPM_CLK10, CPM_CLK_TX); |
240 | cpm2_clk_setup(CPM_CLK_FCC2, CPM_CLK13, CPM_CLK_RX); |
241 | cpm2_clk_setup(CPM_CLK_FCC2, CPM_CLK14, CPM_CLK_TX); |
242 | } |
243 | |
244 | static void __init ep8248e_setup_arch(void) |
245 | { |
246 | if (ppc_md.progress) |
247 | ppc_md.progress("ep8248e_setup_arch()" , 0); |
248 | |
249 | cpm2_reset(); |
250 | |
251 | /* When this is set, snooping CPM DMA from RAM causes |
252 | * machine checks. See erratum SIU18. |
253 | */ |
254 | clrbits32(&cpm2_immr->im_siu_conf.siu_82xx.sc_bcr, MPC82XX_BCR_PLDP); |
255 | |
256 | ep8248e_bcsr_node = |
257 | of_find_compatible_node(NULL, NULL, compat: "fsl,ep8248e-bcsr" ); |
258 | if (!ep8248e_bcsr_node) { |
259 | printk(KERN_ERR "No bcsr in device tree\n" ); |
260 | return; |
261 | } |
262 | |
263 | ep8248e_bcsr = of_iomap(ep8248e_bcsr_node, 0); |
264 | if (!ep8248e_bcsr) { |
265 | printk(KERN_ERR "Cannot map BCSR registers\n" ); |
266 | of_node_put(node: ep8248e_bcsr_node); |
267 | ep8248e_bcsr_node = NULL; |
268 | return; |
269 | } |
270 | |
271 | setbits8(&ep8248e_bcsr[7], BCSR7_SCC2_ENABLE); |
272 | setbits8(&ep8248e_bcsr[8], BCSR8_PHY1_ENABLE | BCSR8_PHY1_POWER | |
273 | BCSR8_PHY2_ENABLE | BCSR8_PHY2_POWER); |
274 | |
275 | init_ioports(); |
276 | |
277 | if (ppc_md.progress) |
278 | ppc_md.progress("ep8248e_setup_arch(), finish" , 0); |
279 | } |
280 | |
281 | static const struct of_device_id of_bus_ids[] __initconst = { |
282 | { .compatible = "simple-bus" , }, |
283 | { .compatible = "fsl,ep8248e-bcsr" , }, |
284 | {}, |
285 | }; |
286 | |
287 | static int __init declare_of_platform_devices(void) |
288 | { |
289 | of_platform_bus_probe(NULL, matches: of_bus_ids, NULL); |
290 | |
291 | if (IS_ENABLED(CONFIG_MDIO_BITBANG)) |
292 | platform_driver_register(&ep8248e_mdio_driver); |
293 | |
294 | return 0; |
295 | } |
296 | machine_device_initcall(ep8248e, declare_of_platform_devices); |
297 | |
298 | define_machine(ep8248e) |
299 | { |
300 | .name = "Embedded Planet EP8248E" , |
301 | .compatible = "fsl,ep8248e" , |
302 | .setup_arch = ep8248e_setup_arch, |
303 | .init_IRQ = ep8248e_pic_init, |
304 | .get_irq = cpm2_get_irq, |
305 | .restart = pq2_restart, |
306 | .progress = udbg_progress, |
307 | }; |
308 | |