1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * Synopsys DWC Ethernet Quality-of-Service v4.10a linux driver 4 * 5 * Copyright (C) 2016 Joao Pinto <jpinto@synopsys.com> 6 */ 7 8 #include <linux/clk.h> 9 #include <linux/clk-provider.h> 10 #include <linux/device.h> 11 #include <linux/gpio/consumer.h> 12 #include <linux/ethtool.h> 13 #include <linux/io.h> 14 #include <linux/iopoll.h> 15 #include <linux/ioport.h> 16 #include <linux/module.h> 17 #include <linux/of.h> 18 #include <linux/of_net.h> 19 #include <linux/mfd/syscon.h> 20 #include <linux/platform_device.h> 21 #include <linux/reset.h> 22 #include <linux/stmmac.h> 23 24 #include "stmmac_platform.h" 25 #include "dwmac4.h" 26 27 struct tegra_eqos { 28 struct device *dev; 29 void __iomem *regs; 30 31 struct reset_control *rst; 32 33 struct gpio_desc *reset; 34 }; 35 36 static int dwc_eth_dwmac_config_dt(struct platform_device *pdev, 37 struct plat_stmmacenet_data *plat_dat) 38 { 39 struct device *dev = &pdev->dev; 40 u32 burst_map = 0; 41 u32 bit_index = 0; 42 u32 a_index = 0; 43 44 if (!plat_dat->axi) { 45 plat_dat->axi = devm_kzalloc(&pdev->dev, 46 sizeof(struct stmmac_axi), 47 GFP_KERNEL); 48 49 if (!plat_dat->axi) 50 return -ENOMEM; 51 } 52 53 plat_dat->axi->axi_lpi_en = device_property_read_bool(dev, 54 "snps,en-lpi"); 55 if (device_property_read_u32(dev, "snps,write-requests", 56 &plat_dat->axi->axi_wr_osr_lmt)) { 57 /** 58 * Since the register has a reset value of 1, if property 59 * is missing, default to 1. 60 */ 61 plat_dat->axi->axi_wr_osr_lmt = 1; 62 } else { 63 /** 64 * If property exists, to keep the behavior from dwc_eth_qos, 65 * subtract one after parsing. 66 */ 67 plat_dat->axi->axi_wr_osr_lmt--; 68 } 69 70 if (device_property_read_u32(dev, "snps,read-requests", 71 &plat_dat->axi->axi_rd_osr_lmt)) { 72 /** 73 * Since the register has a reset value of 1, if property 74 * is missing, default to 1. 75 */ 76 plat_dat->axi->axi_rd_osr_lmt = 1; 77 } else { 78 /** 79 * If property exists, to keep the behavior from dwc_eth_qos, 80 * subtract one after parsing. 81 */ 82 plat_dat->axi->axi_rd_osr_lmt--; 83 } 84 device_property_read_u32(dev, "snps,burst-map", &burst_map); 85 86 /* converts burst-map bitmask to burst array */ 87 for (bit_index = 0; bit_index < 7; bit_index++) { 88 if (burst_map & (1 << bit_index)) { 89 switch (bit_index) { 90 case 0: 91 plat_dat->axi->axi_blen[a_index] = 4; break; 92 case 1: 93 plat_dat->axi->axi_blen[a_index] = 8; break; 94 case 2: 95 plat_dat->axi->axi_blen[a_index] = 16; break; 96 case 3: 97 plat_dat->axi->axi_blen[a_index] = 32; break; 98 case 4: 99 plat_dat->axi->axi_blen[a_index] = 64; break; 100 case 5: 101 plat_dat->axi->axi_blen[a_index] = 128; break; 102 case 6: 103 plat_dat->axi->axi_blen[a_index] = 256; break; 104 default: 105 break; 106 } 107 a_index++; 108 } 109 } 110 111 /* dwc-qos needs GMAC4, AAL, TSO and PMT */ 112 plat_dat->has_gmac4 = 1; 113 plat_dat->dma_cfg->aal = 1; 114 plat_dat->flags |= STMMAC_FLAG_TSO_EN; 115 plat_dat->pmt = 1; 116 117 return 0; 118 } 119 120 static int dwc_qos_probe(struct platform_device *pdev, 121 struct plat_stmmacenet_data *plat_dat, 122 struct stmmac_resources *stmmac_res) 123 { 124 plat_dat->pclk = stmmac_pltfr_find_clk(plat_dat, "phy_ref_clk"); 125 126 return 0; 127 } 128 129 #define SDMEMCOMPPADCTRL 0x8800 130 #define SDMEMCOMPPADCTRL_PAD_E_INPUT_OR_E_PWRD BIT(31) 131 132 #define AUTO_CAL_CONFIG 0x8804 133 #define AUTO_CAL_CONFIG_START BIT(31) 134 #define AUTO_CAL_CONFIG_ENABLE BIT(29) 135 136 #define AUTO_CAL_STATUS 0x880c 137 #define AUTO_CAL_STATUS_ACTIVE BIT(31) 138 139 static void tegra_eqos_fix_speed(void *bsp_priv, int speed, unsigned int mode) 140 { 141 struct tegra_eqos *eqos = bsp_priv; 142 bool needs_calibration = false; 143 struct stmmac_priv *priv; 144 u32 value; 145 int err; 146 147 switch (speed) { 148 case SPEED_1000: 149 case SPEED_100: 150 needs_calibration = true; 151 fallthrough; 152 153 case SPEED_10: 154 break; 155 156 default: 157 dev_err(eqos->dev, "invalid speed %d\n", speed); 158 break; 159 } 160 161 if (needs_calibration) { 162 priv = netdev_priv(dev_get_drvdata(eqos->dev)); 163 164 /* Calibration should be done with the MDIO bus idle */ 165 mutex_lock(&priv->mii->mdio_lock); 166 167 /* calibrate */ 168 value = readl(eqos->regs + SDMEMCOMPPADCTRL); 169 value |= SDMEMCOMPPADCTRL_PAD_E_INPUT_OR_E_PWRD; 170 writel(value, eqos->regs + SDMEMCOMPPADCTRL); 171 172 udelay(1); 173 174 value = readl(eqos->regs + AUTO_CAL_CONFIG); 175 value |= AUTO_CAL_CONFIG_START | AUTO_CAL_CONFIG_ENABLE; 176 writel(value, eqos->regs + AUTO_CAL_CONFIG); 177 178 err = readl_poll_timeout_atomic(eqos->regs + AUTO_CAL_STATUS, 179 value, 180 value & AUTO_CAL_STATUS_ACTIVE, 181 1, 10); 182 if (err < 0) { 183 dev_err(eqos->dev, "calibration did not start\n"); 184 goto failed; 185 } 186 187 err = readl_poll_timeout_atomic(eqos->regs + AUTO_CAL_STATUS, 188 value, 189 (value & AUTO_CAL_STATUS_ACTIVE) == 0, 190 20, 200); 191 if (err < 0) { 192 dev_err(eqos->dev, "calibration didn't finish\n"); 193 goto failed; 194 } 195 196 failed: 197 value = readl(eqos->regs + SDMEMCOMPPADCTRL); 198 value &= ~SDMEMCOMPPADCTRL_PAD_E_INPUT_OR_E_PWRD; 199 writel(value, eqos->regs + SDMEMCOMPPADCTRL); 200 201 mutex_unlock(&priv->mii->mdio_lock); 202 } else { 203 value = readl(eqos->regs + AUTO_CAL_CONFIG); 204 value &= ~AUTO_CAL_CONFIG_ENABLE; 205 writel(value, eqos->regs + AUTO_CAL_CONFIG); 206 } 207 } 208 209 static int tegra_eqos_probe(struct platform_device *pdev, 210 struct plat_stmmacenet_data *plat_dat, 211 struct stmmac_resources *res) 212 { 213 struct device *dev = &pdev->dev; 214 struct tegra_eqos *eqos; 215 int err; 216 217 eqos = devm_kzalloc(&pdev->dev, sizeof(*eqos), GFP_KERNEL); 218 if (!eqos) 219 return -ENOMEM; 220 221 eqos->dev = &pdev->dev; 222 eqos->regs = res->addr; 223 224 if (!is_of_node(dev->fwnode)) 225 goto bypass_clk_reset_gpio; 226 227 plat_dat->clk_tx_i = stmmac_pltfr_find_clk(plat_dat, "tx"); 228 229 eqos->reset = devm_gpiod_get(&pdev->dev, "phy-reset", GPIOD_OUT_HIGH); 230 if (IS_ERR(eqos->reset)) { 231 err = PTR_ERR(eqos->reset); 232 return err; 233 } 234 235 usleep_range(2000, 4000); 236 gpiod_set_value(eqos->reset, 0); 237 238 /* MDIO bus was already reset just above */ 239 plat_dat->mdio_bus_data->needs_reset = false; 240 241 eqos->rst = devm_reset_control_get(&pdev->dev, "eqos"); 242 if (IS_ERR(eqos->rst)) { 243 err = PTR_ERR(eqos->rst); 244 goto reset_phy; 245 } 246 247 err = reset_control_assert(eqos->rst); 248 if (err < 0) 249 goto reset_phy; 250 251 usleep_range(2000, 4000); 252 253 err = reset_control_deassert(eqos->rst); 254 if (err < 0) 255 goto reset_phy; 256 257 usleep_range(2000, 4000); 258 259 bypass_clk_reset_gpio: 260 plat_dat->fix_mac_speed = tegra_eqos_fix_speed; 261 plat_dat->set_clk_tx_rate = stmmac_set_clk_tx_rate; 262 plat_dat->bsp_priv = eqos; 263 plat_dat->flags |= STMMAC_FLAG_SPH_DISABLE | 264 STMMAC_FLAG_EN_TX_LPI_CLK_PHY_CAP | 265 STMMAC_FLAG_USE_PHY_WOL; 266 267 return 0; 268 269 reset_phy: 270 gpiod_set_value(eqos->reset, 1); 271 272 return err; 273 } 274 275 static void tegra_eqos_remove(struct platform_device *pdev) 276 { 277 struct tegra_eqos *eqos = get_stmmac_bsp_priv(&pdev->dev); 278 279 reset_control_assert(eqos->rst); 280 gpiod_set_value(eqos->reset, 1); 281 } 282 283 struct dwc_eth_dwmac_data { 284 int (*probe)(struct platform_device *pdev, 285 struct plat_stmmacenet_data *plat_dat, 286 struct stmmac_resources *res); 287 void (*remove)(struct platform_device *pdev); 288 const char *stmmac_clk_name; 289 }; 290 291 static const struct dwc_eth_dwmac_data dwc_qos_data = { 292 .probe = dwc_qos_probe, 293 .stmmac_clk_name = "apb_pclk", 294 }; 295 296 static const struct dwc_eth_dwmac_data tegra_eqos_data = { 297 .probe = tegra_eqos_probe, 298 .remove = tegra_eqos_remove, 299 .stmmac_clk_name = "slave_bus", 300 }; 301 302 static const struct dwc_eth_dwmac_data fsd_eqos_data = { 303 .stmmac_clk_name = "slave_bus", 304 }; 305 306 static int dwc_eth_dwmac_probe(struct platform_device *pdev) 307 { 308 const struct dwc_eth_dwmac_data *data; 309 struct plat_stmmacenet_data *plat_dat; 310 struct stmmac_resources stmmac_res; 311 int ret; 312 313 data = device_get_match_data(&pdev->dev); 314 315 memset(&stmmac_res, 0, sizeof(struct stmmac_resources)); 316 317 /** 318 * Since stmmac_platform supports name IRQ only, basic platform 319 * resource initialization is done in the glue logic. 320 */ 321 stmmac_res.irq = platform_get_irq(pdev, 0); 322 if (stmmac_res.irq < 0) 323 return stmmac_res.irq; 324 stmmac_res.wol_irq = stmmac_res.irq; 325 326 stmmac_res.addr = devm_platform_ioremap_resource(pdev, 0); 327 if (IS_ERR(stmmac_res.addr)) 328 return PTR_ERR(stmmac_res.addr); 329 330 plat_dat = devm_stmmac_probe_config_dt(pdev, stmmac_res.mac); 331 if (IS_ERR(plat_dat)) 332 return PTR_ERR(plat_dat); 333 334 ret = devm_clk_bulk_get_all_enabled(&pdev->dev, &plat_dat->clks); 335 if (ret < 0) 336 return dev_err_probe(&pdev->dev, ret, "Failed to retrieve and enable all required clocks\n"); 337 plat_dat->num_clks = ret; 338 339 plat_dat->stmmac_clk = stmmac_pltfr_find_clk(plat_dat, 340 data->stmmac_clk_name); 341 342 if (data->probe) 343 ret = data->probe(pdev, plat_dat, &stmmac_res); 344 if (ret < 0) { 345 dev_err_probe(&pdev->dev, ret, "failed to probe subdriver\n"); 346 return ret; 347 } 348 349 ret = dwc_eth_dwmac_config_dt(pdev, plat_dat); 350 if (ret) 351 goto remove; 352 353 ret = stmmac_dvr_probe(&pdev->dev, plat_dat, &stmmac_res); 354 if (ret) 355 goto remove; 356 357 return ret; 358 359 remove: 360 if (data->remove) 361 data->remove(pdev); 362 363 return ret; 364 } 365 366 static void dwc_eth_dwmac_remove(struct platform_device *pdev) 367 { 368 const struct dwc_eth_dwmac_data *data = device_get_match_data(&pdev->dev); 369 370 stmmac_dvr_remove(&pdev->dev); 371 372 if (data->remove) 373 data->remove(pdev); 374 } 375 376 static const struct of_device_id dwc_eth_dwmac_match[] = { 377 { .compatible = "snps,dwc-qos-ethernet-4.10", .data = &dwc_qos_data }, 378 { .compatible = "nvidia,tegra186-eqos", .data = &tegra_eqos_data }, 379 { .compatible = "tesla,fsd-ethqos", .data = &fsd_eqos_data }, 380 { } 381 }; 382 MODULE_DEVICE_TABLE(of, dwc_eth_dwmac_match); 383 384 static struct platform_driver dwc_eth_dwmac_driver = { 385 .probe = dwc_eth_dwmac_probe, 386 .remove = dwc_eth_dwmac_remove, 387 .driver = { 388 .name = "dwc-eth-dwmac", 389 .pm = &stmmac_pltfr_pm_ops, 390 .of_match_table = dwc_eth_dwmac_match, 391 }, 392 }; 393 module_platform_driver(dwc_eth_dwmac_driver); 394 395 MODULE_AUTHOR("Joao Pinto <jpinto@synopsys.com>"); 396 MODULE_DESCRIPTION("Synopsys DWC Ethernet Quality-of-Service v4.10a driver"); 397 MODULE_LICENSE("GPL v2"); 398