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