494 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * Synopsys DWC Ethernet Quality-of-Service v4.10a linux driver4 *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 27struct tegra_eqos {28 struct device *dev;29 void __iomem *regs;30 31 struct reset_control *rst;32 struct clk *clk_master;33 struct clk *clk_slave;34 struct clk *clk_tx;35 struct clk *clk_rx;36 37 struct gpio_desc *reset;38};39 40static int dwc_eth_dwmac_config_dt(struct platform_device *pdev,41 struct plat_stmmacenet_data *plat_dat)42{43 struct device *dev = &pdev->dev;44 u32 burst_map = 0;45 u32 bit_index = 0;46 u32 a_index = 0;47 48 if (!plat_dat->axi) {49 plat_dat->axi = kzalloc(sizeof(struct stmmac_axi), GFP_KERNEL);50 51 if (!plat_dat->axi)52 return -ENOMEM;53 }54 55 plat_dat->axi->axi_lpi_en = device_property_read_bool(dev,56 "snps,en-lpi");57 if (device_property_read_u32(dev, "snps,write-requests",58 &plat_dat->axi->axi_wr_osr_lmt)) {59 /**60 * Since the register has a reset value of 1, if property61 * is missing, default to 1.62 */63 plat_dat->axi->axi_wr_osr_lmt = 1;64 } else {65 /**66 * If property exists, to keep the behavior from dwc_eth_qos,67 * subtract one after parsing.68 */69 plat_dat->axi->axi_wr_osr_lmt--;70 }71 72 if (device_property_read_u32(dev, "snps,read-requests",73 &plat_dat->axi->axi_rd_osr_lmt)) {74 /**75 * Since the register has a reset value of 1, if property76 * is missing, default to 1.77 */78 plat_dat->axi->axi_rd_osr_lmt = 1;79 } else {80 /**81 * If property exists, to keep the behavior from dwc_eth_qos,82 * subtract one after parsing.83 */84 plat_dat->axi->axi_rd_osr_lmt--;85 }86 device_property_read_u32(dev, "snps,burst-map", &burst_map);87 88 /* converts burst-map bitmask to burst array */89 for (bit_index = 0; bit_index < 7; bit_index++) {90 if (burst_map & (1 << bit_index)) {91 switch (bit_index) {92 case 0:93 plat_dat->axi->axi_blen[a_index] = 4; break;94 case 1:95 plat_dat->axi->axi_blen[a_index] = 8; break;96 case 2:97 plat_dat->axi->axi_blen[a_index] = 16; break;98 case 3:99 plat_dat->axi->axi_blen[a_index] = 32; break;100 case 4:101 plat_dat->axi->axi_blen[a_index] = 64; break;102 case 5:103 plat_dat->axi->axi_blen[a_index] = 128; break;104 case 6:105 plat_dat->axi->axi_blen[a_index] = 256; break;106 default:107 break;108 }109 a_index++;110 }111 }112 113 /* dwc-qos needs GMAC4, AAL, TSO and PMT */114 plat_dat->has_gmac4 = 1;115 plat_dat->dma_cfg->aal = 1;116 plat_dat->flags |= STMMAC_FLAG_TSO_EN;117 plat_dat->pmt = 1;118 119 return 0;120}121 122static int dwc_qos_probe(struct platform_device *pdev,123 struct plat_stmmacenet_data *plat_dat,124 struct stmmac_resources *stmmac_res)125{126 int err;127 128 plat_dat->stmmac_clk = devm_clk_get(&pdev->dev, "apb_pclk");129 if (IS_ERR(plat_dat->stmmac_clk)) {130 dev_err(&pdev->dev, "apb_pclk clock not found.\n");131 return PTR_ERR(plat_dat->stmmac_clk);132 }133 134 err = clk_prepare_enable(plat_dat->stmmac_clk);135 if (err < 0) {136 dev_err(&pdev->dev, "failed to enable apb_pclk clock: %d\n",137 err);138 return err;139 }140 141 plat_dat->pclk = devm_clk_get(&pdev->dev, "phy_ref_clk");142 if (IS_ERR(plat_dat->pclk)) {143 dev_err(&pdev->dev, "phy_ref_clk clock not found.\n");144 err = PTR_ERR(plat_dat->pclk);145 goto disable;146 }147 148 err = clk_prepare_enable(plat_dat->pclk);149 if (err < 0) {150 dev_err(&pdev->dev, "failed to enable phy_ref clock: %d\n",151 err);152 goto disable;153 }154 155 return 0;156 157disable:158 clk_disable_unprepare(plat_dat->stmmac_clk);159 return err;160}161 162static void dwc_qos_remove(struct platform_device *pdev)163{164 struct net_device *ndev = platform_get_drvdata(pdev);165 struct stmmac_priv *priv = netdev_priv(ndev);166 167 clk_disable_unprepare(priv->plat->pclk);168 clk_disable_unprepare(priv->plat->stmmac_clk);169}170 171#define SDMEMCOMPPADCTRL 0x8800172#define SDMEMCOMPPADCTRL_PAD_E_INPUT_OR_E_PWRD BIT(31)173 174#define AUTO_CAL_CONFIG 0x8804175#define AUTO_CAL_CONFIG_START BIT(31)176#define AUTO_CAL_CONFIG_ENABLE BIT(29)177 178#define AUTO_CAL_STATUS 0x880c179#define AUTO_CAL_STATUS_ACTIVE BIT(31)180 181static void tegra_eqos_fix_speed(void *priv, unsigned int speed, unsigned int mode)182{183 struct tegra_eqos *eqos = priv;184 unsigned long rate = 125000000;185 bool needs_calibration = false;186 u32 value;187 int err;188 189 switch (speed) {190 case SPEED_1000:191 needs_calibration = true;192 rate = 125000000;193 break;194 195 case SPEED_100:196 needs_calibration = true;197 rate = 25000000;198 break;199 200 case SPEED_10:201 rate = 2500000;202 break;203 204 default:205 dev_err(eqos->dev, "invalid speed %u\n", speed);206 break;207 }208 209 if (needs_calibration) {210 /* calibrate */211 value = readl(eqos->regs + SDMEMCOMPPADCTRL);212 value |= SDMEMCOMPPADCTRL_PAD_E_INPUT_OR_E_PWRD;213 writel(value, eqos->regs + SDMEMCOMPPADCTRL);214 215 udelay(1);216 217 value = readl(eqos->regs + AUTO_CAL_CONFIG);218 value |= AUTO_CAL_CONFIG_START | AUTO_CAL_CONFIG_ENABLE;219 writel(value, eqos->regs + AUTO_CAL_CONFIG);220 221 err = readl_poll_timeout_atomic(eqos->regs + AUTO_CAL_STATUS,222 value,223 value & AUTO_CAL_STATUS_ACTIVE,224 1, 10);225 if (err < 0) {226 dev_err(eqos->dev, "calibration did not start\n");227 goto failed;228 }229 230 err = readl_poll_timeout_atomic(eqos->regs + AUTO_CAL_STATUS,231 value,232 (value & AUTO_CAL_STATUS_ACTIVE) == 0,233 20, 200);234 if (err < 0) {235 dev_err(eqos->dev, "calibration didn't finish\n");236 goto failed;237 }238 239 failed:240 value = readl(eqos->regs + SDMEMCOMPPADCTRL);241 value &= ~SDMEMCOMPPADCTRL_PAD_E_INPUT_OR_E_PWRD;242 writel(value, eqos->regs + SDMEMCOMPPADCTRL);243 } else {244 value = readl(eqos->regs + AUTO_CAL_CONFIG);245 value &= ~AUTO_CAL_CONFIG_ENABLE;246 writel(value, eqos->regs + AUTO_CAL_CONFIG);247 }248 249 err = clk_set_rate(eqos->clk_tx, rate);250 if (err < 0)251 dev_err(eqos->dev, "failed to set TX rate: %d\n", err);252}253 254static int tegra_eqos_init(struct platform_device *pdev, void *priv)255{256 struct tegra_eqos *eqos = priv;257 unsigned long rate;258 u32 value;259 260 rate = clk_get_rate(eqos->clk_slave);261 262 value = (rate / 1000000) - 1;263 writel(value, eqos->regs + GMAC_1US_TIC_COUNTER);264 265 return 0;266}267 268static int tegra_eqos_probe(struct platform_device *pdev,269 struct plat_stmmacenet_data *data,270 struct stmmac_resources *res)271{272 struct device *dev = &pdev->dev;273 struct tegra_eqos *eqos;274 int err;275 276 eqos = devm_kzalloc(&pdev->dev, sizeof(*eqos), GFP_KERNEL);277 if (!eqos)278 return -ENOMEM;279 280 eqos->dev = &pdev->dev;281 eqos->regs = res->addr;282 283 if (!is_of_node(dev->fwnode))284 goto bypass_clk_reset_gpio;285 286 eqos->clk_master = devm_clk_get(&pdev->dev, "master_bus");287 if (IS_ERR(eqos->clk_master)) {288 err = PTR_ERR(eqos->clk_master);289 goto error;290 }291 292 err = clk_prepare_enable(eqos->clk_master);293 if (err < 0)294 goto error;295 296 eqos->clk_slave = devm_clk_get(&pdev->dev, "slave_bus");297 if (IS_ERR(eqos->clk_slave)) {298 err = PTR_ERR(eqos->clk_slave);299 goto disable_master;300 }301 302 data->stmmac_clk = eqos->clk_slave;303 304 err = clk_prepare_enable(eqos->clk_slave);305 if (err < 0)306 goto disable_master;307 308 eqos->clk_rx = devm_clk_get(&pdev->dev, "rx");309 if (IS_ERR(eqos->clk_rx)) {310 err = PTR_ERR(eqos->clk_rx);311 goto disable_slave;312 }313 314 err = clk_prepare_enable(eqos->clk_rx);315 if (err < 0)316 goto disable_slave;317 318 eqos->clk_tx = devm_clk_get(&pdev->dev, "tx");319 if (IS_ERR(eqos->clk_tx)) {320 err = PTR_ERR(eqos->clk_tx);321 goto disable_rx;322 }323 324 err = clk_prepare_enable(eqos->clk_tx);325 if (err < 0)326 goto disable_rx;327 328 eqos->reset = devm_gpiod_get(&pdev->dev, "phy-reset", GPIOD_OUT_HIGH);329 if (IS_ERR(eqos->reset)) {330 err = PTR_ERR(eqos->reset);331 goto disable_tx;332 }333 334 usleep_range(2000, 4000);335 gpiod_set_value(eqos->reset, 0);336 337 /* MDIO bus was already reset just above */338 data->mdio_bus_data->needs_reset = false;339 340 eqos->rst = devm_reset_control_get(&pdev->dev, "eqos");341 if (IS_ERR(eqos->rst)) {342 err = PTR_ERR(eqos->rst);343 goto reset_phy;344 }345 346 err = reset_control_assert(eqos->rst);347 if (err < 0)348 goto reset_phy;349 350 usleep_range(2000, 4000);351 352 err = reset_control_deassert(eqos->rst);353 if (err < 0)354 goto reset_phy;355 356 usleep_range(2000, 4000);357 358bypass_clk_reset_gpio:359 data->fix_mac_speed = tegra_eqos_fix_speed;360 data->init = tegra_eqos_init;361 data->bsp_priv = eqos;362 data->flags |= STMMAC_FLAG_SPH_DISABLE;363 364 err = tegra_eqos_init(pdev, eqos);365 if (err < 0)366 goto reset;367 368 return 0;369reset:370 reset_control_assert(eqos->rst);371reset_phy:372 gpiod_set_value(eqos->reset, 1);373disable_tx:374 clk_disable_unprepare(eqos->clk_tx);375disable_rx:376 clk_disable_unprepare(eqos->clk_rx);377disable_slave:378 clk_disable_unprepare(eqos->clk_slave);379disable_master:380 clk_disable_unprepare(eqos->clk_master);381error:382 return err;383}384 385static void tegra_eqos_remove(struct platform_device *pdev)386{387 struct tegra_eqos *eqos = get_stmmac_bsp_priv(&pdev->dev);388 389 reset_control_assert(eqos->rst);390 gpiod_set_value(eqos->reset, 1);391 clk_disable_unprepare(eqos->clk_tx);392 clk_disable_unprepare(eqos->clk_rx);393 clk_disable_unprepare(eqos->clk_slave);394 clk_disable_unprepare(eqos->clk_master);395}396 397struct dwc_eth_dwmac_data {398 int (*probe)(struct platform_device *pdev,399 struct plat_stmmacenet_data *data,400 struct stmmac_resources *res);401 void (*remove)(struct platform_device *pdev);402};403 404static const struct dwc_eth_dwmac_data dwc_qos_data = {405 .probe = dwc_qos_probe,406 .remove = dwc_qos_remove,407};408 409static const struct dwc_eth_dwmac_data tegra_eqos_data = {410 .probe = tegra_eqos_probe,411 .remove = tegra_eqos_remove,412};413 414static int dwc_eth_dwmac_probe(struct platform_device *pdev)415{416 const struct dwc_eth_dwmac_data *data;417 struct plat_stmmacenet_data *plat_dat;418 struct stmmac_resources stmmac_res;419 int ret;420 421 data = device_get_match_data(&pdev->dev);422 423 memset(&stmmac_res, 0, sizeof(struct stmmac_resources));424 425 /**426 * Since stmmac_platform supports name IRQ only, basic platform427 * resource initialization is done in the glue logic.428 */429 stmmac_res.irq = platform_get_irq(pdev, 0);430 if (stmmac_res.irq < 0)431 return stmmac_res.irq;432 stmmac_res.wol_irq = stmmac_res.irq;433 434 stmmac_res.addr = devm_platform_ioremap_resource(pdev, 0);435 if (IS_ERR(stmmac_res.addr))436 return PTR_ERR(stmmac_res.addr);437 438 plat_dat = devm_stmmac_probe_config_dt(pdev, stmmac_res.mac);439 if (IS_ERR(plat_dat))440 return PTR_ERR(plat_dat);441 442 ret = data->probe(pdev, plat_dat, &stmmac_res);443 if (ret < 0) {444 dev_err_probe(&pdev->dev, ret, "failed to probe subdriver\n");445 return ret;446 }447 448 ret = dwc_eth_dwmac_config_dt(pdev, plat_dat);449 if (ret)450 goto remove;451 452 ret = stmmac_dvr_probe(&pdev->dev, plat_dat, &stmmac_res);453 if (ret)454 goto remove;455 456 return ret;457 458remove:459 data->remove(pdev);460 461 return ret;462}463 464static void dwc_eth_dwmac_remove(struct platform_device *pdev)465{466 const struct dwc_eth_dwmac_data *data = device_get_match_data(&pdev->dev);467 468 stmmac_dvr_remove(&pdev->dev);469 470 data->remove(pdev);471}472 473static const struct of_device_id dwc_eth_dwmac_match[] = {474 { .compatible = "snps,dwc-qos-ethernet-4.10", .data = &dwc_qos_data },475 { .compatible = "nvidia,tegra186-eqos", .data = &tegra_eqos_data },476 { }477};478MODULE_DEVICE_TABLE(of, dwc_eth_dwmac_match);479 480static struct platform_driver dwc_eth_dwmac_driver = {481 .probe = dwc_eth_dwmac_probe,482 .remove_new = dwc_eth_dwmac_remove,483 .driver = {484 .name = "dwc-eth-dwmac",485 .pm = &stmmac_pltfr_pm_ops,486 .of_match_table = dwc_eth_dwmac_match,487 },488};489module_platform_driver(dwc_eth_dwmac_driver);490 491MODULE_AUTHOR("Joao Pinto <jpinto@synopsys.com>");492MODULE_DESCRIPTION("Synopsys DWC Ethernet Quality-of-Service v4.10a driver");493MODULE_LICENSE("GPL v2");494