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