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