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 *priv, int speed, unsigned int mode) 140 { 141 struct tegra_eqos *eqos = priv; 142 bool needs_calibration = false; 143 u32 value; 144 int err; 145 146 switch (speed) { 147 case SPEED_1000: 148 case SPEED_100: 149 needs_calibration = true; 150 fallthrough; 151 152 case SPEED_10: 153 break; 154 155 default: 156 dev_err(eqos->dev, "invalid speed %d\n", speed); 157 break; 158 } 159 160 if (needs_calibration) { 161 /* calibrate */ 162 value = readl(eqos->regs + SDMEMCOMPPADCTRL); 163 value |= SDMEMCOMPPADCTRL_PAD_E_INPUT_OR_E_PWRD; 164 writel(value, eqos->regs + SDMEMCOMPPADCTRL); 165 166 udelay(1); 167 168 value = readl(eqos->regs + AUTO_CAL_CONFIG); 169 value |= AUTO_CAL_CONFIG_START | AUTO_CAL_CONFIG_ENABLE; 170 writel(value, eqos->regs + AUTO_CAL_CONFIG); 171 172 err = readl_poll_timeout_atomic(eqos->regs + AUTO_CAL_STATUS, 173 value, 174 value & AUTO_CAL_STATUS_ACTIVE, 175 1, 10); 176 if (err < 0) { 177 dev_err(eqos->dev, "calibration did not start\n"); 178 goto failed; 179 } 180 181 err = readl_poll_timeout_atomic(eqos->regs + AUTO_CAL_STATUS, 182 value, 183 (value & AUTO_CAL_STATUS_ACTIVE) == 0, 184 20, 200); 185 if (err < 0) { 186 dev_err(eqos->dev, "calibration didn't finish\n"); 187 goto failed; 188 } 189 190 failed: 191 value = readl(eqos->regs + SDMEMCOMPPADCTRL); 192 value &= ~SDMEMCOMPPADCTRL_PAD_E_INPUT_OR_E_PWRD; 193 writel(value, eqos->regs + SDMEMCOMPPADCTRL); 194 } else { 195 value = readl(eqos->regs + AUTO_CAL_CONFIG); 196 value &= ~AUTO_CAL_CONFIG_ENABLE; 197 writel(value, eqos->regs + AUTO_CAL_CONFIG); 198 } 199 } 200 201 static int tegra_eqos_probe(struct platform_device *pdev, 202 struct plat_stmmacenet_data *plat_dat, 203 struct stmmac_resources *res) 204 { 205 struct device *dev = &pdev->dev; 206 struct tegra_eqos *eqos; 207 int err; 208 209 eqos = devm_kzalloc(&pdev->dev, sizeof(*eqos), GFP_KERNEL); 210 if (!eqos) 211 return -ENOMEM; 212 213 eqos->dev = &pdev->dev; 214 eqos->regs = res->addr; 215 216 if (!is_of_node(dev->fwnode)) 217 goto bypass_clk_reset_gpio; 218 219 plat_dat->clk_tx_i = stmmac_pltfr_find_clk(plat_dat, "tx"); 220 221 eqos->reset = devm_gpiod_get(&pdev->dev, "phy-reset", GPIOD_OUT_HIGH); 222 if (IS_ERR(eqos->reset)) { 223 err = PTR_ERR(eqos->reset); 224 return err; 225 } 226 227 usleep_range(2000, 4000); 228 gpiod_set_value(eqos->reset, 0); 229 230 /* MDIO bus was already reset just above */ 231 plat_dat->mdio_bus_data->needs_reset = false; 232 233 eqos->rst = devm_reset_control_get(&pdev->dev, "eqos"); 234 if (IS_ERR(eqos->rst)) { 235 err = PTR_ERR(eqos->rst); 236 goto reset_phy; 237 } 238 239 err = reset_control_assert(eqos->rst); 240 if (err < 0) 241 goto reset_phy; 242 243 usleep_range(2000, 4000); 244 245 err = reset_control_deassert(eqos->rst); 246 if (err < 0) 247 goto reset_phy; 248 249 usleep_range(2000, 4000); 250 251 bypass_clk_reset_gpio: 252 plat_dat->fix_mac_speed = tegra_eqos_fix_speed; 253 plat_dat->set_clk_tx_rate = stmmac_set_clk_tx_rate; 254 plat_dat->bsp_priv = eqos; 255 plat_dat->flags |= STMMAC_FLAG_SPH_DISABLE; 256 257 return 0; 258 259 reset_phy: 260 gpiod_set_value(eqos->reset, 1); 261 262 return err; 263 } 264 265 static void tegra_eqos_remove(struct platform_device *pdev) 266 { 267 struct tegra_eqos *eqos = get_stmmac_bsp_priv(&pdev->dev); 268 269 reset_control_assert(eqos->rst); 270 gpiod_set_value(eqos->reset, 1); 271 } 272 273 struct dwc_eth_dwmac_data { 274 int (*probe)(struct platform_device *pdev, 275 struct plat_stmmacenet_data *plat_dat, 276 struct stmmac_resources *res); 277 void (*remove)(struct platform_device *pdev); 278 const char *stmmac_clk_name; 279 }; 280 281 static const struct dwc_eth_dwmac_data dwc_qos_data = { 282 .probe = dwc_qos_probe, 283 .stmmac_clk_name = "apb_pclk", 284 }; 285 286 static const struct dwc_eth_dwmac_data tegra_eqos_data = { 287 .probe = tegra_eqos_probe, 288 .remove = tegra_eqos_remove, 289 .stmmac_clk_name = "slave_bus", 290 }; 291 292 static const struct dwc_eth_dwmac_data fsd_eqos_data = { 293 .stmmac_clk_name = "slave_bus", 294 }; 295 296 static int dwc_eth_dwmac_probe(struct platform_device *pdev) 297 { 298 const struct dwc_eth_dwmac_data *data; 299 struct plat_stmmacenet_data *plat_dat; 300 struct stmmac_resources stmmac_res; 301 int ret; 302 303 data = device_get_match_data(&pdev->dev); 304 305 memset(&stmmac_res, 0, sizeof(struct stmmac_resources)); 306 307 /** 308 * Since stmmac_platform supports name IRQ only, basic platform 309 * resource initialization is done in the glue logic. 310 */ 311 stmmac_res.irq = platform_get_irq(pdev, 0); 312 if (stmmac_res.irq < 0) 313 return stmmac_res.irq; 314 stmmac_res.wol_irq = stmmac_res.irq; 315 316 stmmac_res.addr = devm_platform_ioremap_resource(pdev, 0); 317 if (IS_ERR(stmmac_res.addr)) 318 return PTR_ERR(stmmac_res.addr); 319 320 plat_dat = devm_stmmac_probe_config_dt(pdev, stmmac_res.mac); 321 if (IS_ERR(plat_dat)) 322 return PTR_ERR(plat_dat); 323 324 ret = devm_clk_bulk_get_all(&pdev->dev, &plat_dat->clks); 325 if (ret < 0) 326 return dev_err_probe(&pdev->dev, ret, "Failed to retrieve all required clocks\n"); 327 plat_dat->num_clks = ret; 328 329 ret = clk_bulk_prepare_enable(plat_dat->num_clks, plat_dat->clks); 330 if (ret) 331 return dev_err_probe(&pdev->dev, ret, "Failed to enable clocks\n"); 332 333 plat_dat->stmmac_clk = stmmac_pltfr_find_clk(plat_dat, 334 data->stmmac_clk_name); 335 336 if (data->probe) 337 ret = data->probe(pdev, plat_dat, &stmmac_res); 338 if (ret < 0) { 339 dev_err_probe(&pdev->dev, ret, "failed to probe subdriver\n"); 340 clk_bulk_disable_unprepare(plat_dat->num_clks, plat_dat->clks); 341 return ret; 342 } 343 344 ret = dwc_eth_dwmac_config_dt(pdev, plat_dat); 345 if (ret) 346 goto remove; 347 348 ret = stmmac_dvr_probe(&pdev->dev, plat_dat, &stmmac_res); 349 if (ret) 350 goto remove; 351 352 return ret; 353 354 remove: 355 if (data->remove) 356 data->remove(pdev); 357 358 return ret; 359 } 360 361 static void dwc_eth_dwmac_remove(struct platform_device *pdev) 362 { 363 const struct dwc_eth_dwmac_data *data = device_get_match_data(&pdev->dev); 364 struct plat_stmmacenet_data *plat_dat = dev_get_platdata(&pdev->dev); 365 366 stmmac_dvr_remove(&pdev->dev); 367 368 if (data->remove) 369 data->remove(pdev); 370 371 if (plat_dat) 372 clk_bulk_disable_unprepare(plat_dat->num_clks, plat_dat->clks); 373 } 374 375 static const struct of_device_id dwc_eth_dwmac_match[] = { 376 { .compatible = "snps,dwc-qos-ethernet-4.10", .data = &dwc_qos_data }, 377 { .compatible = "nvidia,tegra186-eqos", .data = &tegra_eqos_data }, 378 { .compatible = "tesla,fsd-ethqos", .data = &fsd_eqos_data }, 379 { } 380 }; 381 MODULE_DEVICE_TABLE(of, dwc_eth_dwmac_match); 382 383 static struct platform_driver dwc_eth_dwmac_driver = { 384 .probe = dwc_eth_dwmac_probe, 385 .remove = dwc_eth_dwmac_remove, 386 .driver = { 387 .name = "dwc-eth-dwmac", 388 .pm = &stmmac_pltfr_pm_ops, 389 .of_match_table = dwc_eth_dwmac_match, 390 }, 391 }; 392 module_platform_driver(dwc_eth_dwmac_driver); 393 394 MODULE_AUTHOR("Joao Pinto <jpinto@synopsys.com>"); 395 MODULE_DESCRIPTION("Synopsys DWC Ethernet Quality-of-Service v4.10a driver"); 396 MODULE_LICENSE("GPL v2"); 397