1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3 * PHY package support
4 */
5
6 #include <linux/of.h>
7 #include <linux/phy.h>
8
9 #include "phylib.h"
10 #include "phylib-internal.h"
11
12 /**
13 * struct phy_package_shared - Shared information in PHY packages
14 * @base_addr: Base PHY address of PHY package used to combine PHYs
15 * in one package and for offset calculation of phy_package_read/write
16 * @np: Pointer to the Device Node if PHY package defined in DT
17 * @refcnt: Number of PHYs connected to this shared data
18 * @flags: Initialization of PHY package
19 * @priv_size: Size of the shared private data @priv
20 * @priv: Driver private data shared across a PHY package
21 *
22 * Represents a shared structure between different phydev's in the same
23 * package, for example a quad PHY. See phy_package_join() and
24 * phy_package_leave().
25 */
26 struct phy_package_shared {
27 u8 base_addr;
28 /* With PHY package defined in DT this points to the PHY package node */
29 struct device_node *np;
30 refcount_t refcnt;
31 unsigned long flags;
32 size_t priv_size;
33
34 /* private data pointer */
35 /* note that this pointer is shared between different phydevs and
36 * the user has to take care of appropriate locking. It is allocated
37 * and freed automatically by phy_package_join() and
38 * phy_package_leave().
39 */
40 void *priv;
41 };
42
phy_package_get_node(struct phy_device * phydev)43 struct device_node *phy_package_get_node(struct phy_device *phydev)
44 {
45 return phydev->shared->np;
46 }
47 EXPORT_SYMBOL_GPL(phy_package_get_node);
48
phy_package_get_priv(struct phy_device * phydev)49 void *phy_package_get_priv(struct phy_device *phydev)
50 {
51 return phydev->shared->priv;
52 }
53 EXPORT_SYMBOL_GPL(phy_package_get_priv);
54
phy_package_address(struct phy_device * phydev,unsigned int addr_offset)55 static int phy_package_address(struct phy_device *phydev,
56 unsigned int addr_offset)
57 {
58 struct phy_package_shared *shared = phydev->shared;
59 u8 base_addr = shared->base_addr;
60
61 if (addr_offset >= PHY_MAX_ADDR - base_addr)
62 return -EIO;
63
64 /* we know that addr will be in the range 0..31 and thus the
65 * implicit cast to a signed int is not a problem.
66 */
67 return base_addr + addr_offset;
68 }
69
__phy_package_read(struct phy_device * phydev,unsigned int addr_offset,u32 regnum)70 int __phy_package_read(struct phy_device *phydev, unsigned int addr_offset,
71 u32 regnum)
72 {
73 int addr = phy_package_address(phydev, addr_offset);
74
75 if (addr < 0)
76 return addr;
77
78 return __mdiobus_read(phydev->mdio.bus, addr, regnum);
79 }
80 EXPORT_SYMBOL_GPL(__phy_package_read);
81
__phy_package_write(struct phy_device * phydev,unsigned int addr_offset,u32 regnum,u16 val)82 int __phy_package_write(struct phy_device *phydev, unsigned int addr_offset,
83 u32 regnum, u16 val)
84 {
85 int addr = phy_package_address(phydev, addr_offset);
86
87 if (addr < 0)
88 return addr;
89
90 return __mdiobus_write(phydev->mdio.bus, addr, regnum, val);
91 }
92 EXPORT_SYMBOL_GPL(__phy_package_write);
93
94 /**
95 * __phy_package_read_mmd - read MMD reg relative to PHY package base addr
96 * @phydev: The phy_device struct
97 * @addr_offset: The offset to be added to PHY package base_addr
98 * @devad: The MMD to read from
99 * @regnum: The register on the MMD to read
100 *
101 * Convenience helper for reading a register of an MMD on a given PHY
102 * using the PHY package base address. The base address is added to
103 * the addr_offset value.
104 *
105 * Same calling rules as for __phy_read();
106 *
107 * NOTE: It's assumed that the entire PHY package is either C22 or C45.
108 */
__phy_package_read_mmd(struct phy_device * phydev,unsigned int addr_offset,int devad,u32 regnum)109 int __phy_package_read_mmd(struct phy_device *phydev,
110 unsigned int addr_offset, int devad,
111 u32 regnum)
112 {
113 int addr = phy_package_address(phydev, addr_offset);
114
115 if (addr < 0)
116 return addr;
117
118 if (regnum > (u16)~0 || devad > 32)
119 return -EINVAL;
120
121 return mmd_phy_read(phydev->mdio.bus, addr, phydev->is_c45, devad,
122 regnum);
123 }
124 EXPORT_SYMBOL(__phy_package_read_mmd);
125
126 /**
127 * __phy_package_write_mmd - write MMD reg relative to PHY package base addr
128 * @phydev: The phy_device struct
129 * @addr_offset: The offset to be added to PHY package base_addr
130 * @devad: The MMD to write to
131 * @regnum: The register on the MMD to write
132 * @val: value to write to @regnum
133 *
134 * Convenience helper for writing a register of an MMD on a given PHY
135 * using the PHY package base address. The base address is added to
136 * the addr_offset value.
137 *
138 * Same calling rules as for __phy_write();
139 *
140 * NOTE: It's assumed that the entire PHY package is either C22 or C45.
141 */
__phy_package_write_mmd(struct phy_device * phydev,unsigned int addr_offset,int devad,u32 regnum,u16 val)142 int __phy_package_write_mmd(struct phy_device *phydev,
143 unsigned int addr_offset, int devad,
144 u32 regnum, u16 val)
145 {
146 int addr = phy_package_address(phydev, addr_offset);
147
148 if (addr < 0)
149 return addr;
150
151 if (regnum > (u16)~0 || devad > 32)
152 return -EINVAL;
153
154 return mmd_phy_write(phydev->mdio.bus, addr, phydev->is_c45, devad,
155 regnum, val);
156 }
157 EXPORT_SYMBOL(__phy_package_write_mmd);
158
__phy_package_set_once(struct phy_device * phydev,unsigned int b)159 static bool __phy_package_set_once(struct phy_device *phydev, unsigned int b)
160 {
161 struct phy_package_shared *shared = phydev->shared;
162
163 if (!shared)
164 return false;
165
166 return !test_and_set_bit(b, &shared->flags);
167 }
168
phy_package_init_once(struct phy_device * phydev)169 bool phy_package_init_once(struct phy_device *phydev)
170 {
171 return __phy_package_set_once(phydev, 0);
172 }
173 EXPORT_SYMBOL_GPL(phy_package_init_once);
174
phy_package_probe_once(struct phy_device * phydev)175 bool phy_package_probe_once(struct phy_device *phydev)
176 {
177 return __phy_package_set_once(phydev, 1);
178 }
179 EXPORT_SYMBOL_GPL(phy_package_probe_once);
180
181 /**
182 * phy_package_join - join a common PHY group
183 * @phydev: target phy_device struct
184 * @base_addr: cookie and base PHY address of PHY package for offset
185 * calculation of global register access
186 * @priv_size: if non-zero allocate this amount of bytes for private data
187 *
188 * This joins a PHY group and provides a shared storage for all phydevs in
189 * this group. This is intended to be used for packages which contain
190 * more than one PHY, for example a quad PHY transceiver.
191 *
192 * The base_addr parameter serves as cookie which has to have the same values
193 * for all members of one group and as the base PHY address of the PHY package
194 * for offset calculation to access generic registers of a PHY package.
195 * Usually, one of the PHY addresses of the different PHYs in the package
196 * provides access to these global registers.
197 * The address which is given here, will be used in the phy_package_read()
198 * and phy_package_write() convenience functions as base and added to the
199 * passed offset in those functions.
200 *
201 * This will set the shared pointer of the phydev to the shared storage.
202 * If this is the first call for a this cookie the shared storage will be
203 * allocated. If priv_size is non-zero, the given amount of bytes are
204 * allocated for the priv member.
205 *
206 * Returns < 1 on error, 0 on success. Esp. calling phy_package_join()
207 * with the same cookie but a different priv_size is an error.
208 */
phy_package_join(struct phy_device * phydev,int base_addr,size_t priv_size)209 int phy_package_join(struct phy_device *phydev, int base_addr, size_t priv_size)
210 {
211 struct mii_bus *bus = phydev->mdio.bus;
212 struct phy_package_shared *shared;
213 int ret;
214
215 if (base_addr < 0 || base_addr >= PHY_MAX_ADDR)
216 return -EINVAL;
217
218 mutex_lock(&bus->shared_lock);
219 shared = bus->shared[base_addr];
220 if (!shared) {
221 ret = -ENOMEM;
222 shared = kzalloc(sizeof(*shared), GFP_KERNEL);
223 if (!shared)
224 goto err_unlock;
225 if (priv_size) {
226 shared->priv = kzalloc(priv_size, GFP_KERNEL);
227 if (!shared->priv)
228 goto err_free;
229 shared->priv_size = priv_size;
230 }
231 shared->base_addr = base_addr;
232 shared->np = NULL;
233 refcount_set(&shared->refcnt, 1);
234 bus->shared[base_addr] = shared;
235 } else {
236 ret = -EINVAL;
237 if (priv_size && priv_size != shared->priv_size)
238 goto err_unlock;
239 refcount_inc(&shared->refcnt);
240 }
241 mutex_unlock(&bus->shared_lock);
242
243 phydev->shared = shared;
244
245 return 0;
246
247 err_free:
248 kfree(shared);
249 err_unlock:
250 mutex_unlock(&bus->shared_lock);
251 return ret;
252 }
253 EXPORT_SYMBOL_GPL(phy_package_join);
254
255 /**
256 * of_phy_package_join - join a common PHY group in PHY package
257 * @phydev: target phy_device struct
258 * @priv_size: if non-zero allocate this amount of bytes for private data
259 *
260 * This is a variant of phy_package_join for PHY package defined in DT.
261 *
262 * The parent node of the @phydev is checked as a valid PHY package node
263 * structure (by matching the node name "ethernet-phy-package") and the
264 * base_addr for the PHY package is passed to phy_package_join.
265 *
266 * With this configuration the shared struct will also have the np value
267 * filled to use additional DT defined properties in PHY specific
268 * probe_once and config_init_once PHY package OPs.
269 *
270 * Returns < 0 on error, 0 on success. Esp. calling phy_package_join()
271 * with the same cookie but a different priv_size is an error. Or a parent
272 * node is not detected or is not valid or doesn't match the expected node
273 * name for PHY package.
274 */
of_phy_package_join(struct phy_device * phydev,size_t priv_size)275 int of_phy_package_join(struct phy_device *phydev, size_t priv_size)
276 {
277 struct device_node *node = phydev->mdio.dev.of_node;
278 struct device_node *package_node;
279 u32 base_addr;
280 int ret;
281
282 if (!node)
283 return -EINVAL;
284
285 package_node = of_get_parent(node);
286 if (!package_node)
287 return -EINVAL;
288
289 if (!of_node_name_eq(package_node, "ethernet-phy-package")) {
290 ret = -EINVAL;
291 goto exit;
292 }
293
294 if (of_property_read_u32(package_node, "reg", &base_addr)) {
295 ret = -EINVAL;
296 goto exit;
297 }
298
299 ret = phy_package_join(phydev, base_addr, priv_size);
300 if (ret)
301 goto exit;
302
303 phydev->shared->np = package_node;
304
305 return 0;
306 exit:
307 of_node_put(package_node);
308 return ret;
309 }
310 EXPORT_SYMBOL_GPL(of_phy_package_join);
311
312 /**
313 * phy_package_leave - leave a common PHY group
314 * @phydev: target phy_device struct
315 *
316 * This leaves a PHY group created by phy_package_join(). If this phydev
317 * was the last user of the shared data between the group, this data is
318 * freed. Resets the phydev->shared pointer to NULL.
319 */
phy_package_leave(struct phy_device * phydev)320 void phy_package_leave(struct phy_device *phydev)
321 {
322 struct phy_package_shared *shared = phydev->shared;
323 struct mii_bus *bus = phydev->mdio.bus;
324
325 if (!shared)
326 return;
327
328 /* Decrease the node refcount on leave if present */
329 if (shared->np)
330 of_node_put(shared->np);
331
332 if (refcount_dec_and_mutex_lock(&shared->refcnt, &bus->shared_lock)) {
333 bus->shared[shared->base_addr] = NULL;
334 mutex_unlock(&bus->shared_lock);
335 kfree(shared->priv);
336 kfree(shared);
337 }
338
339 phydev->shared = NULL;
340 }
341 EXPORT_SYMBOL_GPL(phy_package_leave);
342
devm_phy_package_leave(struct device * dev,void * res)343 static void devm_phy_package_leave(struct device *dev, void *res)
344 {
345 phy_package_leave(*(struct phy_device **)res);
346 }
347
348 /**
349 * devm_phy_package_join - resource managed phy_package_join()
350 * @dev: device that is registering this PHY package
351 * @phydev: target phy_device struct
352 * @base_addr: cookie and base PHY address of PHY package for offset
353 * calculation of global register access
354 * @priv_size: if non-zero allocate this amount of bytes for private data
355 *
356 * Managed phy_package_join(). Shared storage fetched by this function,
357 * phy_package_leave() is automatically called on driver detach. See
358 * phy_package_join() for more information.
359 */
devm_phy_package_join(struct device * dev,struct phy_device * phydev,int base_addr,size_t priv_size)360 int devm_phy_package_join(struct device *dev, struct phy_device *phydev,
361 int base_addr, size_t priv_size)
362 {
363 struct phy_device **ptr;
364 int ret;
365
366 ptr = devres_alloc(devm_phy_package_leave, sizeof(*ptr),
367 GFP_KERNEL);
368 if (!ptr)
369 return -ENOMEM;
370
371 ret = phy_package_join(phydev, base_addr, priv_size);
372
373 if (!ret) {
374 *ptr = phydev;
375 devres_add(dev, ptr);
376 } else {
377 devres_free(ptr);
378 }
379
380 return ret;
381 }
382 EXPORT_SYMBOL_GPL(devm_phy_package_join);
383
384 /**
385 * devm_of_phy_package_join - resource managed of_phy_package_join()
386 * @dev: device that is registering this PHY package
387 * @phydev: target phy_device struct
388 * @priv_size: if non-zero allocate this amount of bytes for private data
389 *
390 * Managed of_phy_package_join(). Shared storage fetched by this function,
391 * phy_package_leave() is automatically called on driver detach. See
392 * of_phy_package_join() for more information.
393 */
devm_of_phy_package_join(struct device * dev,struct phy_device * phydev,size_t priv_size)394 int devm_of_phy_package_join(struct device *dev, struct phy_device *phydev,
395 size_t priv_size)
396 {
397 struct phy_device **ptr;
398 int ret;
399
400 ptr = devres_alloc(devm_phy_package_leave, sizeof(*ptr),
401 GFP_KERNEL);
402 if (!ptr)
403 return -ENOMEM;
404
405 ret = of_phy_package_join(phydev, priv_size);
406
407 if (!ret) {
408 *ptr = phydev;
409 devres_add(dev, ptr);
410 } else {
411 devres_free(ptr);
412 }
413
414 return ret;
415 }
416 EXPORT_SYMBOL_GPL(devm_of_phy_package_join);
417
418 MODULE_DESCRIPTION("PHY package support");
419 MODULE_LICENSE("GPL");
420