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 11 struct device_node *phy_package_get_node(struct phy_device *phydev) 12 { 13 return phydev->shared->np; 14 } 15 EXPORT_SYMBOL_GPL(phy_package_get_node); 16 17 void *phy_package_get_priv(struct phy_device *phydev) 18 { 19 return phydev->shared->priv; 20 } 21 EXPORT_SYMBOL_GPL(phy_package_get_priv); 22 23 /** 24 * phy_package_join - join a common PHY group 25 * @phydev: target phy_device struct 26 * @base_addr: cookie and base PHY address of PHY package for offset 27 * calculation of global register access 28 * @priv_size: if non-zero allocate this amount of bytes for private data 29 * 30 * This joins a PHY group and provides a shared storage for all phydevs in 31 * this group. This is intended to be used for packages which contain 32 * more than one PHY, for example a quad PHY transceiver. 33 * 34 * The base_addr parameter serves as cookie which has to have the same values 35 * for all members of one group and as the base PHY address of the PHY package 36 * for offset calculation to access generic registers of a PHY package. 37 * Usually, one of the PHY addresses of the different PHYs in the package 38 * provides access to these global registers. 39 * The address which is given here, will be used in the phy_package_read() 40 * and phy_package_write() convenience functions as base and added to the 41 * passed offset in those functions. 42 * 43 * This will set the shared pointer of the phydev to the shared storage. 44 * If this is the first call for a this cookie the shared storage will be 45 * allocated. If priv_size is non-zero, the given amount of bytes are 46 * allocated for the priv member. 47 * 48 * Returns < 1 on error, 0 on success. Esp. calling phy_package_join() 49 * with the same cookie but a different priv_size is an error. 50 */ 51 int phy_package_join(struct phy_device *phydev, int base_addr, size_t priv_size) 52 { 53 struct mii_bus *bus = phydev->mdio.bus; 54 struct phy_package_shared *shared; 55 int ret; 56 57 if (base_addr < 0 || base_addr >= PHY_MAX_ADDR) 58 return -EINVAL; 59 60 mutex_lock(&bus->shared_lock); 61 shared = bus->shared[base_addr]; 62 if (!shared) { 63 ret = -ENOMEM; 64 shared = kzalloc(sizeof(*shared), GFP_KERNEL); 65 if (!shared) 66 goto err_unlock; 67 if (priv_size) { 68 shared->priv = kzalloc(priv_size, GFP_KERNEL); 69 if (!shared->priv) 70 goto err_free; 71 shared->priv_size = priv_size; 72 } 73 shared->base_addr = base_addr; 74 shared->np = NULL; 75 refcount_set(&shared->refcnt, 1); 76 bus->shared[base_addr] = shared; 77 } else { 78 ret = -EINVAL; 79 if (priv_size && priv_size != shared->priv_size) 80 goto err_unlock; 81 refcount_inc(&shared->refcnt); 82 } 83 mutex_unlock(&bus->shared_lock); 84 85 phydev->shared = shared; 86 87 return 0; 88 89 err_free: 90 kfree(shared); 91 err_unlock: 92 mutex_unlock(&bus->shared_lock); 93 return ret; 94 } 95 EXPORT_SYMBOL_GPL(phy_package_join); 96 97 /** 98 * of_phy_package_join - join a common PHY group in PHY package 99 * @phydev: target phy_device struct 100 * @priv_size: if non-zero allocate this amount of bytes for private data 101 * 102 * This is a variant of phy_package_join for PHY package defined in DT. 103 * 104 * The parent node of the @phydev is checked as a valid PHY package node 105 * structure (by matching the node name "ethernet-phy-package") and the 106 * base_addr for the PHY package is passed to phy_package_join. 107 * 108 * With this configuration the shared struct will also have the np value 109 * filled to use additional DT defined properties in PHY specific 110 * probe_once and config_init_once PHY package OPs. 111 * 112 * Returns < 0 on error, 0 on success. Esp. calling phy_package_join() 113 * with the same cookie but a different priv_size is an error. Or a parent 114 * node is not detected or is not valid or doesn't match the expected node 115 * name for PHY package. 116 */ 117 int of_phy_package_join(struct phy_device *phydev, size_t priv_size) 118 { 119 struct device_node *node = phydev->mdio.dev.of_node; 120 struct device_node *package_node; 121 u32 base_addr; 122 int ret; 123 124 if (!node) 125 return -EINVAL; 126 127 package_node = of_get_parent(node); 128 if (!package_node) 129 return -EINVAL; 130 131 if (!of_node_name_eq(package_node, "ethernet-phy-package")) { 132 ret = -EINVAL; 133 goto exit; 134 } 135 136 if (of_property_read_u32(package_node, "reg", &base_addr)) { 137 ret = -EINVAL; 138 goto exit; 139 } 140 141 ret = phy_package_join(phydev, base_addr, priv_size); 142 if (ret) 143 goto exit; 144 145 phydev->shared->np = package_node; 146 147 return 0; 148 exit: 149 of_node_put(package_node); 150 return ret; 151 } 152 EXPORT_SYMBOL_GPL(of_phy_package_join); 153 154 /** 155 * phy_package_leave - leave a common PHY group 156 * @phydev: target phy_device struct 157 * 158 * This leaves a PHY group created by phy_package_join(). If this phydev 159 * was the last user of the shared data between the group, this data is 160 * freed. Resets the phydev->shared pointer to NULL. 161 */ 162 void phy_package_leave(struct phy_device *phydev) 163 { 164 struct phy_package_shared *shared = phydev->shared; 165 struct mii_bus *bus = phydev->mdio.bus; 166 167 if (!shared) 168 return; 169 170 /* Decrease the node refcount on leave if present */ 171 if (shared->np) 172 of_node_put(shared->np); 173 174 if (refcount_dec_and_mutex_lock(&shared->refcnt, &bus->shared_lock)) { 175 bus->shared[shared->base_addr] = NULL; 176 mutex_unlock(&bus->shared_lock); 177 kfree(shared->priv); 178 kfree(shared); 179 } 180 181 phydev->shared = NULL; 182 } 183 EXPORT_SYMBOL_GPL(phy_package_leave); 184 185 static void devm_phy_package_leave(struct device *dev, void *res) 186 { 187 phy_package_leave(*(struct phy_device **)res); 188 } 189 190 /** 191 * devm_phy_package_join - resource managed phy_package_join() 192 * @dev: device that is registering this PHY package 193 * @phydev: target phy_device struct 194 * @base_addr: cookie and base PHY address of PHY package for offset 195 * calculation of global register access 196 * @priv_size: if non-zero allocate this amount of bytes for private data 197 * 198 * Managed phy_package_join(). Shared storage fetched by this function, 199 * phy_package_leave() is automatically called on driver detach. See 200 * phy_package_join() for more information. 201 */ 202 int devm_phy_package_join(struct device *dev, struct phy_device *phydev, 203 int base_addr, size_t priv_size) 204 { 205 struct phy_device **ptr; 206 int ret; 207 208 ptr = devres_alloc(devm_phy_package_leave, sizeof(*ptr), 209 GFP_KERNEL); 210 if (!ptr) 211 return -ENOMEM; 212 213 ret = phy_package_join(phydev, base_addr, priv_size); 214 215 if (!ret) { 216 *ptr = phydev; 217 devres_add(dev, ptr); 218 } else { 219 devres_free(ptr); 220 } 221 222 return ret; 223 } 224 EXPORT_SYMBOL_GPL(devm_phy_package_join); 225 226 /** 227 * devm_of_phy_package_join - resource managed of_phy_package_join() 228 * @dev: device that is registering this PHY package 229 * @phydev: target phy_device struct 230 * @priv_size: if non-zero allocate this amount of bytes for private data 231 * 232 * Managed of_phy_package_join(). Shared storage fetched by this function, 233 * phy_package_leave() is automatically called on driver detach. See 234 * of_phy_package_join() for more information. 235 */ 236 int devm_of_phy_package_join(struct device *dev, struct phy_device *phydev, 237 size_t priv_size) 238 { 239 struct phy_device **ptr; 240 int ret; 241 242 ptr = devres_alloc(devm_phy_package_leave, sizeof(*ptr), 243 GFP_KERNEL); 244 if (!ptr) 245 return -ENOMEM; 246 247 ret = of_phy_package_join(phydev, priv_size); 248 249 if (!ret) { 250 *ptr = phydev; 251 devres_add(dev, ptr); 252 } else { 253 devres_free(ptr); 254 } 255 256 return ret; 257 } 258 EXPORT_SYMBOL_GPL(devm_of_phy_package_join); 259