root/drivers/net/ethernet/ti/cpsw-phy-sel.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. cpsw_gmii_sel_am3352
  2. cpsw_gmii_sel_dra7xx
  3. match
  4. cpsw_phy_sel
  5. cpsw_phy_sel_probe

   1 // SPDX-License-Identifier: GPL-2.0
   2 /* Texas Instruments Ethernet Switch Driver
   3  *
   4  * Copyright (C) 2013 Texas Instruments
   5  *
   6  * Module Author: Mugunthan V N <mugunthanvnm@ti.com>
   7  *
   8  */
   9 
  10 #include <linux/platform_device.h>
  11 #include <linux/init.h>
  12 #include <linux/netdevice.h>
  13 #include <linux/phy.h>
  14 #include <linux/of.h>
  15 #include <linux/of_device.h>
  16 
  17 #include "cpsw.h"
  18 
  19 /* AM33xx SoC specific definitions for the CONTROL port */
  20 #define AM33XX_GMII_SEL_MODE_MII        0
  21 #define AM33XX_GMII_SEL_MODE_RMII       1
  22 #define AM33XX_GMII_SEL_MODE_RGMII      2
  23 
  24 #define AM33XX_GMII_SEL_RMII2_IO_CLK_EN BIT(7)
  25 #define AM33XX_GMII_SEL_RMII1_IO_CLK_EN BIT(6)
  26 #define AM33XX_GMII_SEL_RGMII2_IDMODE   BIT(5)
  27 #define AM33XX_GMII_SEL_RGMII1_IDMODE   BIT(4)
  28 
  29 #define GMII_SEL_MODE_MASK              0x3
  30 
  31 struct cpsw_phy_sel_priv {
  32         struct device   *dev;
  33         u32 __iomem     *gmii_sel;
  34         bool            rmii_clock_external;
  35         void (*cpsw_phy_sel)(struct cpsw_phy_sel_priv *priv,
  36                              phy_interface_t phy_mode, int slave);
  37 };
  38 
  39 
  40 static void cpsw_gmii_sel_am3352(struct cpsw_phy_sel_priv *priv,
  41                                  phy_interface_t phy_mode, int slave)
  42 {
  43         u32 reg;
  44         u32 mask;
  45         u32 mode = 0;
  46         bool rgmii_id = false;
  47 
  48         reg = readl(priv->gmii_sel);
  49 
  50         switch (phy_mode) {
  51         case PHY_INTERFACE_MODE_RMII:
  52                 mode = AM33XX_GMII_SEL_MODE_RMII;
  53                 break;
  54 
  55         case PHY_INTERFACE_MODE_RGMII:
  56                 mode = AM33XX_GMII_SEL_MODE_RGMII;
  57                 break;
  58 
  59         case PHY_INTERFACE_MODE_RGMII_ID:
  60         case PHY_INTERFACE_MODE_RGMII_RXID:
  61         case PHY_INTERFACE_MODE_RGMII_TXID:
  62                 mode = AM33XX_GMII_SEL_MODE_RGMII;
  63                 rgmii_id = true;
  64                 break;
  65 
  66         default:
  67                 dev_warn(priv->dev,
  68                          "Unsupported PHY mode: \"%s\". Defaulting to MII.\n",
  69                         phy_modes(phy_mode));
  70                 /* fallthrough */
  71         case PHY_INTERFACE_MODE_MII:
  72                 mode = AM33XX_GMII_SEL_MODE_MII;
  73                 break;
  74         }
  75 
  76         mask = GMII_SEL_MODE_MASK << (slave * 2) | BIT(slave + 6);
  77         mask |= BIT(slave + 4);
  78         mode <<= slave * 2;
  79 
  80         if (priv->rmii_clock_external) {
  81                 if (slave == 0)
  82                         mode |= AM33XX_GMII_SEL_RMII1_IO_CLK_EN;
  83                 else
  84                         mode |= AM33XX_GMII_SEL_RMII2_IO_CLK_EN;
  85         }
  86 
  87         if (rgmii_id) {
  88                 if (slave == 0)
  89                         mode |= AM33XX_GMII_SEL_RGMII1_IDMODE;
  90                 else
  91                         mode |= AM33XX_GMII_SEL_RGMII2_IDMODE;
  92         }
  93 
  94         reg &= ~mask;
  95         reg |= mode;
  96 
  97         writel(reg, priv->gmii_sel);
  98 }
  99 
 100 static void cpsw_gmii_sel_dra7xx(struct cpsw_phy_sel_priv *priv,
 101                                  phy_interface_t phy_mode, int slave)
 102 {
 103         u32 reg;
 104         u32 mask;
 105         u32 mode = 0;
 106 
 107         reg = readl(priv->gmii_sel);
 108 
 109         switch (phy_mode) {
 110         case PHY_INTERFACE_MODE_RMII:
 111                 mode = AM33XX_GMII_SEL_MODE_RMII;
 112                 break;
 113 
 114         case PHY_INTERFACE_MODE_RGMII:
 115         case PHY_INTERFACE_MODE_RGMII_ID:
 116         case PHY_INTERFACE_MODE_RGMII_RXID:
 117         case PHY_INTERFACE_MODE_RGMII_TXID:
 118                 mode = AM33XX_GMII_SEL_MODE_RGMII;
 119                 break;
 120 
 121         default:
 122                 dev_warn(priv->dev,
 123                          "Unsupported PHY mode: \"%s\". Defaulting to MII.\n",
 124                         phy_modes(phy_mode));
 125                 /* fallthrough */
 126         case PHY_INTERFACE_MODE_MII:
 127                 mode = AM33XX_GMII_SEL_MODE_MII;
 128                 break;
 129         }
 130 
 131         switch (slave) {
 132         case 0:
 133                 mask = GMII_SEL_MODE_MASK;
 134                 break;
 135         case 1:
 136                 mask = GMII_SEL_MODE_MASK << 4;
 137                 mode <<= 4;
 138                 break;
 139         default:
 140                 dev_err(priv->dev, "invalid slave number...\n");
 141                 return;
 142         }
 143 
 144         if (priv->rmii_clock_external)
 145                 dev_err(priv->dev, "RMII External clock is not supported\n");
 146 
 147         reg &= ~mask;
 148         reg |= mode;
 149 
 150         writel(reg, priv->gmii_sel);
 151 }
 152 
 153 static struct platform_driver cpsw_phy_sel_driver;
 154 static int match(struct device *dev, const void *data)
 155 {
 156         const struct device_node *node = (const struct device_node *)data;
 157         return dev->of_node == node &&
 158                 dev->driver == &cpsw_phy_sel_driver.driver;
 159 }
 160 
 161 void cpsw_phy_sel(struct device *dev, phy_interface_t phy_mode, int slave)
 162 {
 163         struct device_node *node;
 164         struct cpsw_phy_sel_priv *priv;
 165 
 166         node = of_parse_phandle(dev->of_node, "cpsw-phy-sel", 0);
 167         if (!node) {
 168                 node = of_get_child_by_name(dev->of_node, "cpsw-phy-sel");
 169                 if (!node) {
 170                         dev_err(dev, "Phy mode driver DT not found\n");
 171                         return;
 172                 }
 173         }
 174 
 175         dev = bus_find_device(&platform_bus_type, NULL, node, match);
 176         if (!dev) {
 177                 dev_err(dev, "unable to find platform device for %pOF\n", node);
 178                 goto out;
 179         }
 180 
 181         priv = dev_get_drvdata(dev);
 182 
 183         priv->cpsw_phy_sel(priv, phy_mode, slave);
 184 
 185         put_device(dev);
 186 out:
 187         of_node_put(node);
 188 }
 189 EXPORT_SYMBOL_GPL(cpsw_phy_sel);
 190 
 191 static const struct of_device_id cpsw_phy_sel_id_table[] = {
 192         {
 193                 .compatible     = "ti,am3352-cpsw-phy-sel",
 194                 .data           = &cpsw_gmii_sel_am3352,
 195         },
 196         {
 197                 .compatible     = "ti,dra7xx-cpsw-phy-sel",
 198                 .data           = &cpsw_gmii_sel_dra7xx,
 199         },
 200         {
 201                 .compatible     = "ti,am43xx-cpsw-phy-sel",
 202                 .data           = &cpsw_gmii_sel_am3352,
 203         },
 204         {}
 205 };
 206 
 207 static int cpsw_phy_sel_probe(struct platform_device *pdev)
 208 {
 209         struct resource *res;
 210         const struct of_device_id *of_id;
 211         struct cpsw_phy_sel_priv *priv;
 212 
 213         of_id = of_match_node(cpsw_phy_sel_id_table, pdev->dev.of_node);
 214         if (!of_id)
 215                 return -EINVAL;
 216 
 217         priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
 218         if (!priv) {
 219                 dev_err(&pdev->dev, "unable to alloc memory for cpsw phy sel\n");
 220                 return -ENOMEM;
 221         }
 222 
 223         priv->dev = &pdev->dev;
 224         priv->cpsw_phy_sel = of_id->data;
 225 
 226         res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "gmii-sel");
 227         priv->gmii_sel = devm_ioremap_resource(&pdev->dev, res);
 228         if (IS_ERR(priv->gmii_sel))
 229                 return PTR_ERR(priv->gmii_sel);
 230 
 231         if (of_find_property(pdev->dev.of_node, "rmii-clock-ext", NULL))
 232                 priv->rmii_clock_external = true;
 233 
 234         dev_set_drvdata(&pdev->dev, priv);
 235 
 236         return 0;
 237 }
 238 
 239 static struct platform_driver cpsw_phy_sel_driver = {
 240         .probe          = cpsw_phy_sel_probe,
 241         .driver         = {
 242                 .name   = "cpsw-phy-sel",
 243                 .of_match_table = cpsw_phy_sel_id_table,
 244         },
 245 };
 246 builtin_platform_driver(cpsw_phy_sel_driver);

/* [<][>][^][v][top][bottom][index][help] */