xref: /linux/drivers/net/phy/phy_package.c (revision 91ec2035134982b98fab0609a9fd8480e8217dc1)
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