1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * dwmac-imx.c - DWMAC Specific Glue layer for NXP imx8 4 * 5 * Copyright 2020 NXP 6 * 7 */ 8 9 #include <linux/clk.h> 10 #include <linux/gpio/consumer.h> 11 #include <linux/kernel.h> 12 #include <linux/mfd/syscon.h> 13 #include <linux/module.h> 14 #include <linux/of.h> 15 #include <linux/of_device.h> 16 #include <linux/of_net.h> 17 #include <linux/phy.h> 18 #include <linux/platform_device.h> 19 #include <linux/pm_wakeirq.h> 20 #include <linux/regmap.h> 21 #include <linux/slab.h> 22 #include <linux/stmmac.h> 23 24 #include "stmmac_platform.h" 25 26 #define GPR_ENET_QOS_INTF_MODE_MASK GENMASK(21, 16) 27 #define GPR_ENET_QOS_INTF_SEL_MII (0x0 << 16) 28 #define GPR_ENET_QOS_INTF_SEL_RMII (0x4 << 16) 29 #define GPR_ENET_QOS_INTF_SEL_RGMII (0x1 << 16) 30 #define GPR_ENET_QOS_CLK_GEN_EN (0x1 << 19) 31 #define GPR_ENET_QOS_CLK_TX_CLK_SEL (0x1 << 20) 32 #define GPR_ENET_QOS_RGMII_EN (0x1 << 21) 33 34 #define MX93_GPR_ENET_QOS_INTF_MODE_MASK GENMASK(3, 0) 35 #define MX93_GPR_ENET_QOS_INTF_SEL_MII (0x0 << 1) 36 #define MX93_GPR_ENET_QOS_INTF_SEL_RMII (0x4 << 1) 37 #define MX93_GPR_ENET_QOS_INTF_SEL_RGMII (0x1 << 1) 38 #define MX93_GPR_ENET_QOS_CLK_GEN_EN (0x1 << 0) 39 40 struct imx_dwmac_ops { 41 u32 addr_width; 42 bool mac_rgmii_txclk_auto_adj; 43 44 int (*set_intf_mode)(struct plat_stmmacenet_data *plat_dat); 45 }; 46 47 struct imx_priv_data { 48 struct device *dev; 49 struct clk *clk_tx; 50 struct clk *clk_mem; 51 struct regmap *intf_regmap; 52 u32 intf_reg_off; 53 bool rmii_refclk_ext; 54 55 const struct imx_dwmac_ops *ops; 56 struct plat_stmmacenet_data *plat_dat; 57 }; 58 59 static int imx8mp_set_intf_mode(struct plat_stmmacenet_data *plat_dat) 60 { 61 struct imx_priv_data *dwmac = plat_dat->bsp_priv; 62 int val; 63 64 switch (plat_dat->interface) { 65 case PHY_INTERFACE_MODE_MII: 66 val = GPR_ENET_QOS_INTF_SEL_MII; 67 break; 68 case PHY_INTERFACE_MODE_RMII: 69 val = GPR_ENET_QOS_INTF_SEL_RMII; 70 val |= (dwmac->rmii_refclk_ext ? 0 : GPR_ENET_QOS_CLK_TX_CLK_SEL); 71 break; 72 case PHY_INTERFACE_MODE_RGMII: 73 case PHY_INTERFACE_MODE_RGMII_ID: 74 case PHY_INTERFACE_MODE_RGMII_RXID: 75 case PHY_INTERFACE_MODE_RGMII_TXID: 76 val = GPR_ENET_QOS_INTF_SEL_RGMII | 77 GPR_ENET_QOS_RGMII_EN; 78 break; 79 default: 80 pr_debug("imx dwmac doesn't support %d interface\n", 81 plat_dat->interface); 82 return -EINVAL; 83 } 84 85 val |= GPR_ENET_QOS_CLK_GEN_EN; 86 return regmap_update_bits(dwmac->intf_regmap, dwmac->intf_reg_off, 87 GPR_ENET_QOS_INTF_MODE_MASK, val); 88 }; 89 90 static int 91 imx8dxl_set_intf_mode(struct plat_stmmacenet_data *plat_dat) 92 { 93 int ret = 0; 94 95 /* TBD: depends on imx8dxl scu interfaces to be upstreamed */ 96 return ret; 97 } 98 99 static int imx93_set_intf_mode(struct plat_stmmacenet_data *plat_dat) 100 { 101 struct imx_priv_data *dwmac = plat_dat->bsp_priv; 102 int val; 103 104 switch (plat_dat->interface) { 105 case PHY_INTERFACE_MODE_MII: 106 val = MX93_GPR_ENET_QOS_INTF_SEL_MII; 107 break; 108 case PHY_INTERFACE_MODE_RMII: 109 val = MX93_GPR_ENET_QOS_INTF_SEL_RMII; 110 break; 111 case PHY_INTERFACE_MODE_RGMII: 112 case PHY_INTERFACE_MODE_RGMII_ID: 113 case PHY_INTERFACE_MODE_RGMII_RXID: 114 case PHY_INTERFACE_MODE_RGMII_TXID: 115 val = MX93_GPR_ENET_QOS_INTF_SEL_RGMII; 116 break; 117 default: 118 dev_dbg(dwmac->dev, "imx dwmac doesn't support %d interface\n", 119 plat_dat->interface); 120 return -EINVAL; 121 } 122 123 val |= MX93_GPR_ENET_QOS_CLK_GEN_EN; 124 return regmap_update_bits(dwmac->intf_regmap, dwmac->intf_reg_off, 125 MX93_GPR_ENET_QOS_INTF_MODE_MASK, val); 126 }; 127 128 static int imx_dwmac_clks_config(void *priv, bool enabled) 129 { 130 struct imx_priv_data *dwmac = priv; 131 int ret = 0; 132 133 if (enabled) { 134 ret = clk_prepare_enable(dwmac->clk_mem); 135 if (ret) { 136 dev_err(dwmac->dev, "mem clock enable failed\n"); 137 return ret; 138 } 139 140 ret = clk_prepare_enable(dwmac->clk_tx); 141 if (ret) { 142 dev_err(dwmac->dev, "tx clock enable failed\n"); 143 clk_disable_unprepare(dwmac->clk_mem); 144 return ret; 145 } 146 } else { 147 clk_disable_unprepare(dwmac->clk_tx); 148 clk_disable_unprepare(dwmac->clk_mem); 149 } 150 151 return ret; 152 } 153 154 static int imx_dwmac_init(struct platform_device *pdev, void *priv) 155 { 156 struct plat_stmmacenet_data *plat_dat; 157 struct imx_priv_data *dwmac = priv; 158 int ret; 159 160 plat_dat = dwmac->plat_dat; 161 162 if (dwmac->ops->set_intf_mode) { 163 ret = dwmac->ops->set_intf_mode(plat_dat); 164 if (ret) 165 return ret; 166 } 167 168 return 0; 169 } 170 171 static void imx_dwmac_exit(struct platform_device *pdev, void *priv) 172 { 173 /* nothing to do now */ 174 } 175 176 static void imx_dwmac_fix_speed(void *priv, unsigned int speed) 177 { 178 struct plat_stmmacenet_data *plat_dat; 179 struct imx_priv_data *dwmac = priv; 180 unsigned long rate; 181 int err; 182 183 plat_dat = dwmac->plat_dat; 184 185 if (dwmac->ops->mac_rgmii_txclk_auto_adj || 186 (plat_dat->interface == PHY_INTERFACE_MODE_RMII) || 187 (plat_dat->interface == PHY_INTERFACE_MODE_MII)) 188 return; 189 190 switch (speed) { 191 case SPEED_1000: 192 rate = 125000000; 193 break; 194 case SPEED_100: 195 rate = 25000000; 196 break; 197 case SPEED_10: 198 rate = 2500000; 199 break; 200 default: 201 dev_err(dwmac->dev, "invalid speed %u\n", speed); 202 return; 203 } 204 205 err = clk_set_rate(dwmac->clk_tx, rate); 206 if (err < 0) 207 dev_err(dwmac->dev, "failed to set tx rate %lu\n", rate); 208 } 209 210 static int 211 imx_dwmac_parse_dt(struct imx_priv_data *dwmac, struct device *dev) 212 { 213 struct device_node *np = dev->of_node; 214 int err = 0; 215 216 dwmac->rmii_refclk_ext = of_property_read_bool(np, "snps,rmii_refclk_ext"); 217 218 dwmac->clk_tx = devm_clk_get(dev, "tx"); 219 if (IS_ERR(dwmac->clk_tx)) { 220 dev_err(dev, "failed to get tx clock\n"); 221 return PTR_ERR(dwmac->clk_tx); 222 } 223 224 dwmac->clk_mem = NULL; 225 226 if (of_machine_is_compatible("fsl,imx8dxl") || 227 of_machine_is_compatible("fsl,imx93")) { 228 dwmac->clk_mem = devm_clk_get(dev, "mem"); 229 if (IS_ERR(dwmac->clk_mem)) { 230 dev_err(dev, "failed to get mem clock\n"); 231 return PTR_ERR(dwmac->clk_mem); 232 } 233 } 234 235 if (of_machine_is_compatible("fsl,imx8mp") || 236 of_machine_is_compatible("fsl,imx93")) { 237 /* Binding doc describes the propety: 238 * is required by i.MX8MP, i.MX93. 239 * is optinoal for i.MX8DXL. 240 */ 241 dwmac->intf_regmap = syscon_regmap_lookup_by_phandle(np, "intf_mode"); 242 if (IS_ERR(dwmac->intf_regmap)) 243 return PTR_ERR(dwmac->intf_regmap); 244 245 err = of_property_read_u32_index(np, "intf_mode", 1, &dwmac->intf_reg_off); 246 if (err) { 247 dev_err(dev, "Can't get intf mode reg offset (%d)\n", err); 248 return err; 249 } 250 } 251 252 return err; 253 } 254 255 static int imx_dwmac_probe(struct platform_device *pdev) 256 { 257 struct plat_stmmacenet_data *plat_dat; 258 struct stmmac_resources stmmac_res; 259 struct imx_priv_data *dwmac; 260 const struct imx_dwmac_ops *data; 261 int ret; 262 263 ret = stmmac_get_platform_resources(pdev, &stmmac_res); 264 if (ret) 265 return ret; 266 267 dwmac = devm_kzalloc(&pdev->dev, sizeof(*dwmac), GFP_KERNEL); 268 if (!dwmac) 269 return -ENOMEM; 270 271 plat_dat = stmmac_probe_config_dt(pdev, stmmac_res.mac); 272 if (IS_ERR(plat_dat)) 273 return PTR_ERR(plat_dat); 274 275 data = of_device_get_match_data(&pdev->dev); 276 if (!data) { 277 dev_err(&pdev->dev, "failed to get match data\n"); 278 ret = -EINVAL; 279 goto err_match_data; 280 } 281 282 dwmac->ops = data; 283 dwmac->dev = &pdev->dev; 284 285 ret = imx_dwmac_parse_dt(dwmac, &pdev->dev); 286 if (ret) { 287 dev_err(&pdev->dev, "failed to parse OF data\n"); 288 goto err_parse_dt; 289 } 290 291 plat_dat->addr64 = dwmac->ops->addr_width; 292 plat_dat->init = imx_dwmac_init; 293 plat_dat->exit = imx_dwmac_exit; 294 plat_dat->clks_config = imx_dwmac_clks_config; 295 plat_dat->fix_mac_speed = imx_dwmac_fix_speed; 296 plat_dat->bsp_priv = dwmac; 297 dwmac->plat_dat = plat_dat; 298 299 ret = imx_dwmac_clks_config(dwmac, true); 300 if (ret) 301 goto err_clks_config; 302 303 ret = imx_dwmac_init(pdev, dwmac); 304 if (ret) 305 goto err_dwmac_init; 306 307 ret = stmmac_dvr_probe(&pdev->dev, plat_dat, &stmmac_res); 308 if (ret) 309 goto err_drv_probe; 310 311 return 0; 312 313 err_drv_probe: 314 imx_dwmac_exit(pdev, plat_dat->bsp_priv); 315 err_dwmac_init: 316 imx_dwmac_clks_config(dwmac, false); 317 err_clks_config: 318 err_parse_dt: 319 err_match_data: 320 stmmac_remove_config_dt(pdev, plat_dat); 321 return ret; 322 } 323 324 static struct imx_dwmac_ops imx8mp_dwmac_data = { 325 .addr_width = 34, 326 .mac_rgmii_txclk_auto_adj = false, 327 .set_intf_mode = imx8mp_set_intf_mode, 328 }; 329 330 static struct imx_dwmac_ops imx8dxl_dwmac_data = { 331 .addr_width = 32, 332 .mac_rgmii_txclk_auto_adj = true, 333 .set_intf_mode = imx8dxl_set_intf_mode, 334 }; 335 336 static struct imx_dwmac_ops imx93_dwmac_data = { 337 .addr_width = 32, 338 .mac_rgmii_txclk_auto_adj = true, 339 .set_intf_mode = imx93_set_intf_mode, 340 }; 341 342 static const struct of_device_id imx_dwmac_match[] = { 343 { .compatible = "nxp,imx8mp-dwmac-eqos", .data = &imx8mp_dwmac_data }, 344 { .compatible = "nxp,imx8dxl-dwmac-eqos", .data = &imx8dxl_dwmac_data }, 345 { .compatible = "nxp,imx93-dwmac-eqos", .data = &imx93_dwmac_data }, 346 { } 347 }; 348 MODULE_DEVICE_TABLE(of, imx_dwmac_match); 349 350 static struct platform_driver imx_dwmac_driver = { 351 .probe = imx_dwmac_probe, 352 .remove = stmmac_pltfr_remove, 353 .driver = { 354 .name = "imx-dwmac", 355 .pm = &stmmac_pltfr_pm_ops, 356 .of_match_table = imx_dwmac_match, 357 }, 358 }; 359 module_platform_driver(imx_dwmac_driver); 360 361 MODULE_AUTHOR("NXP"); 362 MODULE_DESCRIPTION("NXP imx8 DWMAC Specific Glue layer"); 363 MODULE_LICENSE("GPL v2"); 364