Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

phy: ti: gmii-sel: retrieve ports number and base offset from dt

On K3 AM654x/J721E platforms the Port MII mode selection register(s) have
similar format and placed in the System Control Module (SCM) module
sequentially as one register per port, but, depending SOC and CPSW
instance, the base offset and number of ports can be different.

Hence, add possibility to retrieve number of ports and base registers
offset from DT and support for max possible number of ports supported by K3
SoCs like J721E.

Signed-off-by: Grygorii Strashko <grygorii.strashko@ti.com>
Link: https://lore.kernel.org/r/20200828201943.29155-4-grygorii.strashko@ti.com
Signed-off-by: Vinod Koul <vkoul@kernel.org>

authored by

Grygorii Strashko and committed by
Vinod Koul
7f78322c d3fa20b9

+33 -11
+33 -11
drivers/phy/ti/phy-gmii-sel.c
··· 11 11 #include <linux/module.h> 12 12 #include <linux/mfd/syscon.h> 13 13 #include <linux/of.h> 14 + #include <linux/of_address.h> 14 15 #include <linux/of_net.h> 15 16 #include <linux/phy.h> 16 17 #include <linux/phy/phy.h> ··· 42 41 u32 num_ports; 43 42 u32 features; 44 43 const struct reg_field (*regfields)[PHY_GMII_SEL_LAST]; 44 + bool use_of_data; 45 45 }; 46 46 47 47 struct phy_gmii_sel_priv { ··· 51 49 struct regmap *regmap; 52 50 struct phy_provider *phy_provider; 53 51 struct phy_gmii_sel_phy_priv *if_phys; 52 + u32 num_ports; 53 + u32 reg_offset; 54 54 }; 55 55 56 56 static int phy_gmii_sel_mode(struct phy *phy, enum phy_mode mode, int submode) ··· 172 168 173 169 static const 174 170 struct reg_field phy_gmii_sel_fields_am654[][PHY_GMII_SEL_LAST] = { 175 - { 176 - [PHY_GMII_SEL_PORT_MODE] = REG_FIELD(0x4040, 0, 1), 177 - }, 171 + { [PHY_GMII_SEL_PORT_MODE] = REG_FIELD(0x0, 0, 2), }, 172 + { [PHY_GMII_SEL_PORT_MODE] = REG_FIELD(0x4, 0, 2), }, 173 + { [PHY_GMII_SEL_PORT_MODE] = REG_FIELD(0x8, 0, 2), }, 174 + { [PHY_GMII_SEL_PORT_MODE] = REG_FIELD(0xC, 0, 2), }, 175 + { [PHY_GMII_SEL_PORT_MODE] = REG_FIELD(0x10, 0, 2), }, 176 + { [PHY_GMII_SEL_PORT_MODE] = REG_FIELD(0x14, 0, 2), }, 177 + { [PHY_GMII_SEL_PORT_MODE] = REG_FIELD(0x18, 0, 2), }, 178 + { [PHY_GMII_SEL_PORT_MODE] = REG_FIELD(0x1C, 0, 2), }, 178 179 }; 179 180 180 181 static const 181 182 struct phy_gmii_sel_soc_data phy_gmii_sel_soc_am654 = { 182 - .num_ports = 1, 183 + .use_of_data = true, 183 184 .regfields = phy_gmii_sel_fields_am654, 184 185 }; 185 186 ··· 231 222 if (priv->soc_data->features & BIT(PHY_GMII_SEL_RMII_IO_CLK_EN) && 232 223 args->args_count < 2) 233 224 return ERR_PTR(-EINVAL); 234 - if (phy_id > priv->soc_data->num_ports) 225 + if (phy_id > priv->num_ports) 235 226 return ERR_PTR(-EINVAL); 236 227 if (phy_id != priv->if_phys[phy_id - 1].id) 237 228 return ERR_PTR(-EINVAL); ··· 260 251 261 252 fields = soc_data->regfields[port - 1]; 262 253 field = *fields++; 254 + field.reg += priv->reg_offset; 263 255 dev_dbg(dev, "%s field %x %d %d\n", __func__, 264 256 field.reg, field.msb, field.lsb); 265 257 ··· 270 260 if_phy->fields[PHY_GMII_SEL_PORT_MODE] = regfield; 271 261 272 262 field = *fields++; 263 + field.reg += priv->reg_offset; 273 264 if (soc_data->features & BIT(PHY_GMII_SEL_RGMII_ID_MODE)) { 274 265 regfield = devm_regmap_field_alloc(dev, 275 266 priv->regmap, ··· 283 272 } 284 273 285 274 field = *fields; 275 + field.reg += priv->reg_offset; 286 276 if (soc_data->features & BIT(PHY_GMII_SEL_RMII_IO_CLK_EN)) { 287 277 regfield = devm_regmap_field_alloc(dev, 288 278 priv->regmap, ··· 311 299 static int phy_gmii_sel_init_ports(struct phy_gmii_sel_priv *priv) 312 300 { 313 301 const struct phy_gmii_sel_soc_data *soc_data = priv->soc_data; 314 - struct device *dev = priv->dev; 315 302 struct phy_gmii_sel_phy_priv *if_phys; 316 - int i, num_ports, ret; 303 + struct device *dev = priv->dev; 304 + int i, ret; 317 305 318 - num_ports = soc_data->num_ports; 306 + if (soc_data->use_of_data) { 307 + const __be32 *offset; 308 + u64 size; 319 309 320 - if_phys = devm_kcalloc(priv->dev, num_ports, 310 + offset = of_get_address(dev->of_node, 0, &size, NULL); 311 + priv->num_ports = size / sizeof(u32); 312 + if (!priv->num_ports) 313 + return -EINVAL; 314 + priv->reg_offset = __be32_to_cpu(*offset); 315 + } 316 + 317 + if_phys = devm_kcalloc(dev, priv->num_ports, 321 318 sizeof(*if_phys), GFP_KERNEL); 322 319 if (!if_phys) 323 320 return -ENOMEM; 324 - dev_dbg(dev, "%s %d\n", __func__, num_ports); 321 + dev_dbg(dev, "%s %d\n", __func__, priv->num_ports); 325 322 326 - for (i = 0; i < num_ports; i++) { 323 + for (i = 0; i < priv->num_ports; i++) { 327 324 ret = phy_gmii_init_phy(priv, i + 1, &if_phys[i]); 328 325 if (ret) 329 326 return ret; ··· 360 339 361 340 priv->dev = &pdev->dev; 362 341 priv->soc_data = of_id->data; 342 + priv->num_ports = priv->soc_data->num_ports; 363 343 364 344 priv->regmap = syscon_node_to_regmap(node->parent); 365 345 if (IS_ERR(priv->regmap)) {