Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /*
0003  * Texas Instruments CPSW Port's PHY Interface Mode selection Driver
0004  *
0005  * Copyright (C) 2018 Texas Instruments Incorporated - http://www.ti.com/
0006  *
0007  * Based on cpsw-phy-sel.c driver created by Mugunthan V N <mugunthanvnm@ti.com>
0008  */
0009 
0010 #include <linux/platform_device.h>
0011 #include <linux/module.h>
0012 #include <linux/mfd/syscon.h>
0013 #include <linux/of.h>
0014 #include <linux/of_address.h>
0015 #include <linux/of_net.h>
0016 #include <linux/phy.h>
0017 #include <linux/phy/phy.h>
0018 #include <linux/regmap.h>
0019 
0020 /* AM33xx SoC specific definitions for the CONTROL port */
0021 #define AM33XX_GMII_SEL_MODE_MII    0
0022 #define AM33XX_GMII_SEL_MODE_RMII   1
0023 #define AM33XX_GMII_SEL_MODE_RGMII  2
0024 
0025 enum {
0026     PHY_GMII_SEL_PORT_MODE = 0,
0027     PHY_GMII_SEL_RGMII_ID_MODE,
0028     PHY_GMII_SEL_RMII_IO_CLK_EN,
0029     PHY_GMII_SEL_LAST,
0030 };
0031 
0032 struct phy_gmii_sel_phy_priv {
0033     struct phy_gmii_sel_priv *priv;
0034     u32     id;
0035     struct phy  *if_phy;
0036     int     rmii_clock_external;
0037     int     phy_if_mode;
0038     struct regmap_field *fields[PHY_GMII_SEL_LAST];
0039 };
0040 
0041 struct phy_gmii_sel_soc_data {
0042     u32 num_ports;
0043     u32 features;
0044     const struct reg_field (*regfields)[PHY_GMII_SEL_LAST];
0045     bool use_of_data;
0046 };
0047 
0048 struct phy_gmii_sel_priv {
0049     struct device *dev;
0050     const struct phy_gmii_sel_soc_data *soc_data;
0051     struct regmap *regmap;
0052     struct phy_provider *phy_provider;
0053     struct phy_gmii_sel_phy_priv *if_phys;
0054     u32 num_ports;
0055     u32 reg_offset;
0056 };
0057 
0058 static int phy_gmii_sel_mode(struct phy *phy, enum phy_mode mode, int submode)
0059 {
0060     struct phy_gmii_sel_phy_priv *if_phy = phy_get_drvdata(phy);
0061     const struct phy_gmii_sel_soc_data *soc_data = if_phy->priv->soc_data;
0062     struct device *dev = if_phy->priv->dev;
0063     struct regmap_field *regfield;
0064     int ret, rgmii_id = 0;
0065     u32 gmii_sel_mode = 0;
0066 
0067     if (mode != PHY_MODE_ETHERNET)
0068         return -EINVAL;
0069 
0070     switch (submode) {
0071     case PHY_INTERFACE_MODE_RMII:
0072         gmii_sel_mode = AM33XX_GMII_SEL_MODE_RMII;
0073         break;
0074 
0075     case PHY_INTERFACE_MODE_RGMII:
0076     case PHY_INTERFACE_MODE_RGMII_RXID:
0077         gmii_sel_mode = AM33XX_GMII_SEL_MODE_RGMII;
0078         break;
0079 
0080     case PHY_INTERFACE_MODE_RGMII_ID:
0081     case PHY_INTERFACE_MODE_RGMII_TXID:
0082         gmii_sel_mode = AM33XX_GMII_SEL_MODE_RGMII;
0083         rgmii_id = 1;
0084         break;
0085 
0086     case PHY_INTERFACE_MODE_MII:
0087     case PHY_INTERFACE_MODE_GMII:
0088         gmii_sel_mode = AM33XX_GMII_SEL_MODE_MII;
0089         break;
0090 
0091     default:
0092         dev_warn(dev, "port%u: unsupported mode: \"%s\"\n",
0093              if_phy->id, phy_modes(submode));
0094         return -EINVAL;
0095     }
0096 
0097     if_phy->phy_if_mode = submode;
0098 
0099     dev_dbg(dev, "%s id:%u mode:%u rgmii_id:%d rmii_clk_ext:%d\n",
0100         __func__, if_phy->id, submode, rgmii_id,
0101         if_phy->rmii_clock_external);
0102 
0103     regfield = if_phy->fields[PHY_GMII_SEL_PORT_MODE];
0104     ret = regmap_field_write(regfield, gmii_sel_mode);
0105     if (ret) {
0106         dev_err(dev, "port%u: set mode fail %d", if_phy->id, ret);
0107         return ret;
0108     }
0109 
0110     if (soc_data->features & BIT(PHY_GMII_SEL_RGMII_ID_MODE) &&
0111         if_phy->fields[PHY_GMII_SEL_RGMII_ID_MODE]) {
0112         regfield = if_phy->fields[PHY_GMII_SEL_RGMII_ID_MODE];
0113         ret = regmap_field_write(regfield, rgmii_id);
0114         if (ret)
0115             return ret;
0116     }
0117 
0118     if (soc_data->features & BIT(PHY_GMII_SEL_RMII_IO_CLK_EN) &&
0119         if_phy->fields[PHY_GMII_SEL_RMII_IO_CLK_EN]) {
0120         regfield = if_phy->fields[PHY_GMII_SEL_RMII_IO_CLK_EN];
0121         ret = regmap_field_write(regfield,
0122                      if_phy->rmii_clock_external);
0123     }
0124 
0125     return 0;
0126 }
0127 
0128 static const
0129 struct reg_field phy_gmii_sel_fields_am33xx[][PHY_GMII_SEL_LAST] = {
0130     {
0131         [PHY_GMII_SEL_PORT_MODE] = REG_FIELD(0x650, 0, 1),
0132         [PHY_GMII_SEL_RGMII_ID_MODE] = REG_FIELD(0x650, 4, 4),
0133         [PHY_GMII_SEL_RMII_IO_CLK_EN] = REG_FIELD(0x650, 6, 6),
0134     },
0135     {
0136         [PHY_GMII_SEL_PORT_MODE] = REG_FIELD(0x650, 2, 3),
0137         [PHY_GMII_SEL_RGMII_ID_MODE] = REG_FIELD(0x650, 5, 5),
0138         [PHY_GMII_SEL_RMII_IO_CLK_EN] = REG_FIELD(0x650, 7, 7),
0139     },
0140 };
0141 
0142 static const
0143 struct phy_gmii_sel_soc_data phy_gmii_sel_soc_am33xx = {
0144     .num_ports = 2,
0145     .features = BIT(PHY_GMII_SEL_RGMII_ID_MODE) |
0146             BIT(PHY_GMII_SEL_RMII_IO_CLK_EN),
0147     .regfields = phy_gmii_sel_fields_am33xx,
0148 };
0149 
0150 static const
0151 struct reg_field phy_gmii_sel_fields_dra7[][PHY_GMII_SEL_LAST] = {
0152     {
0153         [PHY_GMII_SEL_PORT_MODE] = REG_FIELD(0x554, 0, 1),
0154     },
0155     {
0156         [PHY_GMII_SEL_PORT_MODE] = REG_FIELD(0x554, 4, 5),
0157     },
0158 };
0159 
0160 static const
0161 struct phy_gmii_sel_soc_data phy_gmii_sel_soc_dra7 = {
0162     .num_ports = 2,
0163     .regfields = phy_gmii_sel_fields_dra7,
0164 };
0165 
0166 static const
0167 struct phy_gmii_sel_soc_data phy_gmii_sel_soc_dm814 = {
0168     .num_ports = 2,
0169     .features = BIT(PHY_GMII_SEL_RGMII_ID_MODE),
0170     .regfields = phy_gmii_sel_fields_am33xx,
0171 };
0172 
0173 static const
0174 struct reg_field phy_gmii_sel_fields_am654[][PHY_GMII_SEL_LAST] = {
0175     { [PHY_GMII_SEL_PORT_MODE] = REG_FIELD(0x0, 0, 2), },
0176     { [PHY_GMII_SEL_PORT_MODE] = REG_FIELD(0x4, 0, 2), },
0177     { [PHY_GMII_SEL_PORT_MODE] = REG_FIELD(0x8, 0, 2), },
0178     { [PHY_GMII_SEL_PORT_MODE] = REG_FIELD(0xC, 0, 2), },
0179     { [PHY_GMII_SEL_PORT_MODE] = REG_FIELD(0x10, 0, 2), },
0180     { [PHY_GMII_SEL_PORT_MODE] = REG_FIELD(0x14, 0, 2), },
0181     { [PHY_GMII_SEL_PORT_MODE] = REG_FIELD(0x18, 0, 2), },
0182     { [PHY_GMII_SEL_PORT_MODE] = REG_FIELD(0x1C, 0, 2), },
0183 };
0184 
0185 static const
0186 struct phy_gmii_sel_soc_data phy_gmii_sel_soc_am654 = {
0187     .use_of_data = true,
0188     .regfields = phy_gmii_sel_fields_am654,
0189 };
0190 
0191 static const struct of_device_id phy_gmii_sel_id_table[] = {
0192     {
0193         .compatible = "ti,am3352-phy-gmii-sel",
0194         .data       = &phy_gmii_sel_soc_am33xx,
0195     },
0196     {
0197         .compatible = "ti,dra7xx-phy-gmii-sel",
0198         .data       = &phy_gmii_sel_soc_dra7,
0199     },
0200     {
0201         .compatible = "ti,am43xx-phy-gmii-sel",
0202         .data       = &phy_gmii_sel_soc_am33xx,
0203     },
0204     {
0205         .compatible = "ti,dm814-phy-gmii-sel",
0206         .data       = &phy_gmii_sel_soc_dm814,
0207     },
0208     {
0209         .compatible = "ti,am654-phy-gmii-sel",
0210         .data       = &phy_gmii_sel_soc_am654,
0211     },
0212     {}
0213 };
0214 MODULE_DEVICE_TABLE(of, phy_gmii_sel_id_table);
0215 
0216 static const struct phy_ops phy_gmii_sel_ops = {
0217     .set_mode   = phy_gmii_sel_mode,
0218     .owner      = THIS_MODULE,
0219 };
0220 
0221 static struct phy *phy_gmii_sel_of_xlate(struct device *dev,
0222                      struct of_phandle_args *args)
0223 {
0224     struct phy_gmii_sel_priv *priv = dev_get_drvdata(dev);
0225     int phy_id = args->args[0];
0226 
0227     if (args->args_count < 1)
0228         return ERR_PTR(-EINVAL);
0229     if (!priv || !priv->if_phys)
0230         return ERR_PTR(-ENODEV);
0231     if (priv->soc_data->features & BIT(PHY_GMII_SEL_RMII_IO_CLK_EN) &&
0232         args->args_count < 2)
0233         return ERR_PTR(-EINVAL);
0234     if (phy_id > priv->num_ports)
0235         return ERR_PTR(-EINVAL);
0236     if (phy_id != priv->if_phys[phy_id - 1].id)
0237         return ERR_PTR(-EINVAL);
0238 
0239     phy_id--;
0240     if (priv->soc_data->features & BIT(PHY_GMII_SEL_RMII_IO_CLK_EN))
0241         priv->if_phys[phy_id].rmii_clock_external = args->args[1];
0242     dev_dbg(dev, "%s id:%u ext:%d\n", __func__,
0243         priv->if_phys[phy_id].id, args->args[1]);
0244 
0245     return priv->if_phys[phy_id].if_phy;
0246 }
0247 
0248 static int phy_gmii_init_phy(struct phy_gmii_sel_priv *priv, int port,
0249                  struct phy_gmii_sel_phy_priv *if_phy)
0250 {
0251     const struct phy_gmii_sel_soc_data *soc_data = priv->soc_data;
0252     struct device *dev = priv->dev;
0253     const struct reg_field *fields;
0254     struct regmap_field *regfield;
0255     struct reg_field field;
0256     int ret;
0257 
0258     if_phy->id = port;
0259     if_phy->priv = priv;
0260 
0261     fields = soc_data->regfields[port - 1];
0262     field = *fields++;
0263     field.reg += priv->reg_offset;
0264     dev_dbg(dev, "%s field %x %d %d\n", __func__,
0265         field.reg, field.msb, field.lsb);
0266 
0267     regfield = devm_regmap_field_alloc(dev, priv->regmap, field);
0268     if (IS_ERR(regfield))
0269         return PTR_ERR(regfield);
0270     if_phy->fields[PHY_GMII_SEL_PORT_MODE] = regfield;
0271 
0272     field = *fields++;
0273     field.reg += priv->reg_offset;
0274     if (soc_data->features & BIT(PHY_GMII_SEL_RGMII_ID_MODE)) {
0275         regfield = devm_regmap_field_alloc(dev,
0276                            priv->regmap,
0277                            field);
0278         if (IS_ERR(regfield))
0279             return PTR_ERR(regfield);
0280         if_phy->fields[PHY_GMII_SEL_RGMII_ID_MODE] = regfield;
0281         dev_dbg(dev, "%s field %x %d %d\n", __func__,
0282             field.reg, field.msb, field.lsb);
0283     }
0284 
0285     field = *fields;
0286     field.reg += priv->reg_offset;
0287     if (soc_data->features & BIT(PHY_GMII_SEL_RMII_IO_CLK_EN)) {
0288         regfield = devm_regmap_field_alloc(dev,
0289                            priv->regmap,
0290                            field);
0291         if (IS_ERR(regfield))
0292             return PTR_ERR(regfield);
0293         if_phy->fields[PHY_GMII_SEL_RMII_IO_CLK_EN] = regfield;
0294         dev_dbg(dev, "%s field %x %d %d\n", __func__,
0295             field.reg, field.msb, field.lsb);
0296     }
0297 
0298     if_phy->if_phy = devm_phy_create(dev,
0299                      priv->dev->of_node,
0300                      &phy_gmii_sel_ops);
0301     if (IS_ERR(if_phy->if_phy)) {
0302         ret = PTR_ERR(if_phy->if_phy);
0303         dev_err(dev, "Failed to create phy%d %d\n", port, ret);
0304         return ret;
0305     }
0306     phy_set_drvdata(if_phy->if_phy, if_phy);
0307 
0308     return 0;
0309 }
0310 
0311 static int phy_gmii_sel_init_ports(struct phy_gmii_sel_priv *priv)
0312 {
0313     const struct phy_gmii_sel_soc_data *soc_data = priv->soc_data;
0314     struct phy_gmii_sel_phy_priv *if_phys;
0315     struct device *dev = priv->dev;
0316     int i, ret;
0317 
0318     if (soc_data->use_of_data) {
0319         const __be32 *offset;
0320         u64 size;
0321 
0322         offset = of_get_address(dev->of_node, 0, &size, NULL);
0323         if (!offset)
0324             return -EINVAL;
0325         priv->num_ports = size / sizeof(u32);
0326         if (!priv->num_ports)
0327             return -EINVAL;
0328         priv->reg_offset = __be32_to_cpu(*offset);
0329     }
0330 
0331     if_phys = devm_kcalloc(dev, priv->num_ports,
0332                    sizeof(*if_phys), GFP_KERNEL);
0333     if (!if_phys)
0334         return -ENOMEM;
0335     dev_dbg(dev, "%s %d\n", __func__, priv->num_ports);
0336 
0337     for (i = 0; i < priv->num_ports; i++) {
0338         ret = phy_gmii_init_phy(priv, i + 1, &if_phys[i]);
0339         if (ret)
0340             return ret;
0341     }
0342 
0343     priv->if_phys = if_phys;
0344     return 0;
0345 }
0346 
0347 static int phy_gmii_sel_probe(struct platform_device *pdev)
0348 {
0349     struct device *dev = &pdev->dev;
0350     struct device_node *node = dev->of_node;
0351     const struct of_device_id *of_id;
0352     struct phy_gmii_sel_priv *priv;
0353     int ret;
0354 
0355     of_id = of_match_node(phy_gmii_sel_id_table, pdev->dev.of_node);
0356     if (!of_id)
0357         return -EINVAL;
0358 
0359     priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
0360     if (!priv)
0361         return -ENOMEM;
0362 
0363     priv->dev = &pdev->dev;
0364     priv->soc_data = of_id->data;
0365     priv->num_ports = priv->soc_data->num_ports;
0366 
0367     priv->regmap = syscon_node_to_regmap(node->parent);
0368     if (IS_ERR(priv->regmap)) {
0369         ret = PTR_ERR(priv->regmap);
0370         dev_err(dev, "Failed to get syscon %d\n", ret);
0371         return ret;
0372     }
0373 
0374     ret = phy_gmii_sel_init_ports(priv);
0375     if (ret)
0376         return ret;
0377 
0378     dev_set_drvdata(&pdev->dev, priv);
0379 
0380     priv->phy_provider =
0381         devm_of_phy_provider_register(dev,
0382                           phy_gmii_sel_of_xlate);
0383     if (IS_ERR(priv->phy_provider)) {
0384         ret = PTR_ERR(priv->phy_provider);
0385         dev_err(dev, "Failed to create phy provider %d\n", ret);
0386         return ret;
0387     }
0388 
0389     return 0;
0390 }
0391 
0392 static struct platform_driver phy_gmii_sel_driver = {
0393     .probe      = phy_gmii_sel_probe,
0394     .driver     = {
0395         .name   = "phy-gmii-sel",
0396         .of_match_table = phy_gmii_sel_id_table,
0397     },
0398 };
0399 module_platform_driver(phy_gmii_sel_driver);
0400 
0401 MODULE_LICENSE("GPL v2");
0402 MODULE_AUTHOR("Grygorii Strashko <grygorii.strashko@ti.com>");
0403 MODULE_DESCRIPTION("TI CPSW Port's PHY Interface Mode selection Driver");