1 | // SPDX-License-Identifier: GPL-2.0-or-later |
2 | /* |
3 | * drivers/net/ethernet/ibm/emac/rgmii.c |
4 | * |
5 | * Driver for PowerPC 4xx on-chip ethernet controller, RGMII bridge support. |
6 | * |
7 | * Copyright 2007 Benjamin Herrenschmidt, IBM Corp. |
8 | * <benh@kernel.crashing.org> |
9 | * |
10 | * Based on the arch/ppc version of the driver: |
11 | * |
12 | * Copyright (c) 2004, 2005 Zultys Technologies. |
13 | * Eugene Surovegin <eugene.surovegin@zultys.com> or <ebs@ebshome.net> |
14 | * |
15 | * Based on original work by |
16 | * Matt Porter <mporter@kernel.crashing.org> |
17 | * Copyright 2004 MontaVista Software, Inc. |
18 | */ |
19 | #include <linux/slab.h> |
20 | #include <linux/kernel.h> |
21 | #include <linux/ethtool.h> |
22 | #include <linux/of.h> |
23 | #include <linux/of_address.h> |
24 | #include <linux/platform_device.h> |
25 | #include <asm/io.h> |
26 | |
27 | #include "emac.h" |
28 | #include "debug.h" |
29 | |
30 | // XXX FIXME: Axon seems to support a subset of the RGMII, we |
31 | // thus need to take that into account and possibly change some |
32 | // of the bit settings below that don't seem to quite match the |
33 | // AXON spec |
34 | |
35 | /* RGMIIx_FER */ |
36 | #define RGMII_FER_MASK(idx) (0x7 << ((idx) * 4)) |
37 | #define RGMII_FER_RTBI(idx) (0x4 << ((idx) * 4)) |
38 | #define RGMII_FER_RGMII(idx) (0x5 << ((idx) * 4)) |
39 | #define RGMII_FER_TBI(idx) (0x6 << ((idx) * 4)) |
40 | #define RGMII_FER_GMII(idx) (0x7 << ((idx) * 4)) |
41 | #define RGMII_FER_MII(idx) RGMII_FER_GMII(idx) |
42 | |
43 | /* RGMIIx_SSR */ |
44 | #define RGMII_SSR_MASK(idx) (0x7 << ((idx) * 8)) |
45 | #define RGMII_SSR_10(idx) (0x1 << ((idx) * 8)) |
46 | #define RGMII_SSR_100(idx) (0x2 << ((idx) * 8)) |
47 | #define RGMII_SSR_1000(idx) (0x4 << ((idx) * 8)) |
48 | |
49 | /* RGMII bridge supports only GMII/TBI and RGMII/RTBI PHYs */ |
50 | static inline int rgmii_valid_mode(int phy_mode) |
51 | { |
52 | return phy_interface_mode_is_rgmii(mode: phy_mode) || |
53 | phy_mode == PHY_INTERFACE_MODE_GMII || |
54 | phy_mode == PHY_INTERFACE_MODE_MII || |
55 | phy_mode == PHY_INTERFACE_MODE_TBI || |
56 | phy_mode == PHY_INTERFACE_MODE_RTBI; |
57 | } |
58 | |
59 | static inline u32 rgmii_mode_mask(int mode, int input) |
60 | { |
61 | switch (mode) { |
62 | case PHY_INTERFACE_MODE_RGMII: |
63 | case PHY_INTERFACE_MODE_RGMII_ID: |
64 | case PHY_INTERFACE_MODE_RGMII_RXID: |
65 | case PHY_INTERFACE_MODE_RGMII_TXID: |
66 | return RGMII_FER_RGMII(input); |
67 | case PHY_INTERFACE_MODE_TBI: |
68 | return RGMII_FER_TBI(input); |
69 | case PHY_INTERFACE_MODE_GMII: |
70 | return RGMII_FER_GMII(input); |
71 | case PHY_INTERFACE_MODE_MII: |
72 | return RGMII_FER_MII(input); |
73 | case PHY_INTERFACE_MODE_RTBI: |
74 | return RGMII_FER_RTBI(input); |
75 | default: |
76 | BUG(); |
77 | } |
78 | } |
79 | |
80 | int rgmii_attach(struct platform_device *ofdev, int input, int mode) |
81 | { |
82 | struct rgmii_instance *dev = platform_get_drvdata(ofdev); |
83 | struct rgmii_regs __iomem *p = dev->base; |
84 | |
85 | RGMII_DBG(dev, "attach(%d)" NL, input); |
86 | |
87 | /* Check if we need to attach to a RGMII */ |
88 | if (input < 0 || !rgmii_valid_mode(mode)) { |
89 | printk(KERN_ERR "%pOF: unsupported settings !\n" , |
90 | ofdev->dev.of_node); |
91 | return -ENODEV; |
92 | } |
93 | |
94 | mutex_lock(&dev->lock); |
95 | |
96 | /* Enable this input */ |
97 | out_be32(&p->fer, in_be32(&p->fer) | rgmii_mode_mask(mode, input)); |
98 | |
99 | printk(KERN_NOTICE "%pOF: input %d in %s mode\n" , |
100 | ofdev->dev.of_node, input, phy_modes(mode)); |
101 | |
102 | ++dev->users; |
103 | |
104 | mutex_unlock(&dev->lock); |
105 | |
106 | return 0; |
107 | } |
108 | |
109 | void rgmii_set_speed(struct platform_device *ofdev, int input, int speed) |
110 | { |
111 | struct rgmii_instance *dev = platform_get_drvdata(ofdev); |
112 | struct rgmii_regs __iomem *p = dev->base; |
113 | u32 ssr; |
114 | |
115 | mutex_lock(&dev->lock); |
116 | |
117 | ssr = in_be32(&p->ssr) & ~RGMII_SSR_MASK(input); |
118 | |
119 | RGMII_DBG(dev, "speed(%d, %d)" NL, input, speed); |
120 | |
121 | if (speed == SPEED_1000) |
122 | ssr |= RGMII_SSR_1000(input); |
123 | else if (speed == SPEED_100) |
124 | ssr |= RGMII_SSR_100(input); |
125 | else if (speed == SPEED_10) |
126 | ssr |= RGMII_SSR_10(input); |
127 | |
128 | out_be32(&p->ssr, ssr); |
129 | |
130 | mutex_unlock(&dev->lock); |
131 | } |
132 | |
133 | void rgmii_get_mdio(struct platform_device *ofdev, int input) |
134 | { |
135 | struct rgmii_instance *dev = platform_get_drvdata(ofdev); |
136 | struct rgmii_regs __iomem *p = dev->base; |
137 | u32 fer; |
138 | |
139 | RGMII_DBG2(dev, "get_mdio(%d)" NL, input); |
140 | |
141 | if (!(dev->flags & EMAC_RGMII_FLAG_HAS_MDIO)) |
142 | return; |
143 | |
144 | mutex_lock(&dev->lock); |
145 | |
146 | fer = in_be32(&p->fer); |
147 | fer |= 0x00080000u >> input; |
148 | out_be32(&p->fer, fer); |
149 | (void)in_be32(&p->fer); |
150 | |
151 | DBG2(dev, " fer = 0x%08x\n" , fer); |
152 | } |
153 | |
154 | void rgmii_put_mdio(struct platform_device *ofdev, int input) |
155 | { |
156 | struct rgmii_instance *dev = platform_get_drvdata(ofdev); |
157 | struct rgmii_regs __iomem *p = dev->base; |
158 | u32 fer; |
159 | |
160 | RGMII_DBG2(dev, "put_mdio(%d)" NL, input); |
161 | |
162 | if (!(dev->flags & EMAC_RGMII_FLAG_HAS_MDIO)) |
163 | return; |
164 | |
165 | fer = in_be32(&p->fer); |
166 | fer &= ~(0x00080000u >> input); |
167 | out_be32(&p->fer, fer); |
168 | (void)in_be32(&p->fer); |
169 | |
170 | DBG2(dev, " fer = 0x%08x\n" , fer); |
171 | |
172 | mutex_unlock(&dev->lock); |
173 | } |
174 | |
175 | void rgmii_detach(struct platform_device *ofdev, int input) |
176 | { |
177 | struct rgmii_instance *dev = platform_get_drvdata(ofdev); |
178 | struct rgmii_regs __iomem *p; |
179 | |
180 | BUG_ON(!dev || dev->users == 0); |
181 | p = dev->base; |
182 | |
183 | mutex_lock(&dev->lock); |
184 | |
185 | RGMII_DBG(dev, "detach(%d)" NL, input); |
186 | |
187 | /* Disable this input */ |
188 | out_be32(&p->fer, in_be32(&p->fer) & ~RGMII_FER_MASK(input)); |
189 | |
190 | --dev->users; |
191 | |
192 | mutex_unlock(&dev->lock); |
193 | } |
194 | |
195 | int rgmii_get_regs_len(struct platform_device *ofdev) |
196 | { |
197 | return sizeof(struct emac_ethtool_regs_subhdr) + |
198 | sizeof(struct rgmii_regs); |
199 | } |
200 | |
201 | void *rgmii_dump_regs(struct platform_device *ofdev, void *buf) |
202 | { |
203 | struct rgmii_instance *dev = platform_get_drvdata(ofdev); |
204 | struct emac_ethtool_regs_subhdr *hdr = buf; |
205 | struct rgmii_regs *regs = (struct rgmii_regs *)(hdr + 1); |
206 | |
207 | hdr->version = 0; |
208 | hdr->index = 0; /* for now, are there chips with more than one |
209 | * rgmii ? if yes, then we'll add a cell_index |
210 | * like we do for emac |
211 | */ |
212 | memcpy_fromio(regs, dev->base, sizeof(struct rgmii_regs)); |
213 | return regs + 1; |
214 | } |
215 | |
216 | |
217 | static int rgmii_probe(struct platform_device *ofdev) |
218 | { |
219 | struct device_node *np = ofdev->dev.of_node; |
220 | struct rgmii_instance *dev; |
221 | struct resource regs; |
222 | int rc; |
223 | |
224 | rc = -ENOMEM; |
225 | dev = kzalloc(size: sizeof(struct rgmii_instance), GFP_KERNEL); |
226 | if (dev == NULL) |
227 | goto err_gone; |
228 | |
229 | mutex_init(&dev->lock); |
230 | dev->ofdev = ofdev; |
231 | |
232 | rc = -ENXIO; |
233 | if (of_address_to_resource(dev: np, index: 0, r: ®s)) { |
234 | printk(KERN_ERR "%pOF: Can't get registers address\n" , np); |
235 | goto err_free; |
236 | } |
237 | |
238 | rc = -ENOMEM; |
239 | dev->base = (struct rgmii_regs __iomem *)ioremap(offset: regs.start, |
240 | size: sizeof(struct rgmii_regs)); |
241 | if (dev->base == NULL) { |
242 | printk(KERN_ERR "%pOF: Can't map device registers!\n" , np); |
243 | goto err_free; |
244 | } |
245 | |
246 | /* Check for RGMII flags */ |
247 | if (of_property_read_bool(np: ofdev->dev.of_node, propname: "has-mdio" )) |
248 | dev->flags |= EMAC_RGMII_FLAG_HAS_MDIO; |
249 | |
250 | /* CAB lacks the right properties, fix this up */ |
251 | if (of_device_is_compatible(device: ofdev->dev.of_node, "ibm,rgmii-axon" )) |
252 | dev->flags |= EMAC_RGMII_FLAG_HAS_MDIO; |
253 | |
254 | DBG2(dev, " Boot FER = 0x%08x, SSR = 0x%08x\n" , |
255 | in_be32(&dev->base->fer), in_be32(&dev->base->ssr)); |
256 | |
257 | /* Disable all inputs by default */ |
258 | out_be32(&dev->base->fer, 0); |
259 | |
260 | printk(KERN_INFO |
261 | "RGMII %pOF initialized with%s MDIO support\n" , |
262 | ofdev->dev.of_node, |
263 | (dev->flags & EMAC_RGMII_FLAG_HAS_MDIO) ? "" : "out" ); |
264 | |
265 | wmb(); |
266 | platform_set_drvdata(pdev: ofdev, data: dev); |
267 | |
268 | return 0; |
269 | |
270 | err_free: |
271 | kfree(objp: dev); |
272 | err_gone: |
273 | return rc; |
274 | } |
275 | |
276 | static void rgmii_remove(struct platform_device *ofdev) |
277 | { |
278 | struct rgmii_instance *dev = platform_get_drvdata(pdev: ofdev); |
279 | |
280 | WARN_ON(dev->users != 0); |
281 | |
282 | iounmap(addr: dev->base); |
283 | kfree(objp: dev); |
284 | } |
285 | |
286 | static const struct of_device_id rgmii_match[] = |
287 | { |
288 | { |
289 | .compatible = "ibm,rgmii" , |
290 | }, |
291 | { |
292 | .type = "emac-rgmii" , |
293 | }, |
294 | {}, |
295 | }; |
296 | |
297 | static struct platform_driver rgmii_driver = { |
298 | .driver = { |
299 | .name = "emac-rgmii" , |
300 | .of_match_table = rgmii_match, |
301 | }, |
302 | .probe = rgmii_probe, |
303 | .remove_new = rgmii_remove, |
304 | }; |
305 | |
306 | int __init rgmii_init(void) |
307 | { |
308 | return platform_driver_register(&rgmii_driver); |
309 | } |
310 | |
311 | void rgmii_exit(void) |
312 | { |
313 | platform_driver_unregister(&rgmii_driver); |
314 | } |
315 | |