437 lines · c
1// SPDX-License-Identifier: GPL-2.02/*3 * dwmac-imx.c - DWMAC Specific Glue layer for NXP imx84 *5 * Copyright 2020 NXP6 *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_net.h>16#include <linux/phy.h>17#include <linux/platform_device.h>18#include <linux/pm_wakeirq.h>19#include <linux/regmap.h>20#include <linux/slab.h>21#include <linux/stmmac.h>22 23#include "stmmac_platform.h"24 25#define GPR_ENET_QOS_INTF_MODE_MASK GENMASK(21, 16)26#define GPR_ENET_QOS_INTF_SEL_MII (0x0 << 16)27#define GPR_ENET_QOS_INTF_SEL_RMII (0x4 << 16)28#define GPR_ENET_QOS_INTF_SEL_RGMII (0x1 << 16)29#define GPR_ENET_QOS_CLK_GEN_EN (0x1 << 19)30#define GPR_ENET_QOS_CLK_TX_CLK_SEL (0x1 << 20)31#define GPR_ENET_QOS_RGMII_EN (0x1 << 21)32 33#define MX93_GPR_ENET_QOS_INTF_MODE_MASK GENMASK(3, 0)34#define MX93_GPR_ENET_QOS_INTF_MASK GENMASK(3, 1)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#define DMA_BUS_MODE 0x0000100041#define DMA_BUS_MODE_SFT_RESET (0x1 << 0)42#define RMII_RESET_SPEED (0x3 << 14)43#define CTRL_SPEED_MASK GENMASK(15, 14)44 45struct imx_dwmac_ops {46 u32 addr_width;47 u32 flags;48 bool mac_rgmii_txclk_auto_adj;49 50 int (*fix_soc_reset)(void *priv, void __iomem *ioaddr);51 int (*set_intf_mode)(struct plat_stmmacenet_data *plat_dat);52 void (*fix_mac_speed)(void *priv, unsigned int speed, unsigned int mode);53};54 55struct imx_priv_data {56 struct device *dev;57 struct clk *clk_tx;58 struct clk *clk_mem;59 struct regmap *intf_regmap;60 u32 intf_reg_off;61 bool rmii_refclk_ext;62 void __iomem *base_addr;63 64 const struct imx_dwmac_ops *ops;65 struct plat_stmmacenet_data *plat_dat;66};67 68static int imx8mp_set_intf_mode(struct plat_stmmacenet_data *plat_dat)69{70 struct imx_priv_data *dwmac = plat_dat->bsp_priv;71 int val;72 73 switch (plat_dat->mac_interface) {74 case PHY_INTERFACE_MODE_MII:75 val = GPR_ENET_QOS_INTF_SEL_MII;76 break;77 case PHY_INTERFACE_MODE_RMII:78 val = GPR_ENET_QOS_INTF_SEL_RMII;79 val |= (dwmac->rmii_refclk_ext ? 0 : GPR_ENET_QOS_CLK_TX_CLK_SEL);80 break;81 case PHY_INTERFACE_MODE_RGMII:82 case PHY_INTERFACE_MODE_RGMII_ID:83 case PHY_INTERFACE_MODE_RGMII_RXID:84 case PHY_INTERFACE_MODE_RGMII_TXID:85 val = GPR_ENET_QOS_INTF_SEL_RGMII |86 GPR_ENET_QOS_RGMII_EN;87 break;88 default:89 pr_debug("imx dwmac doesn't support %d interface\n",90 plat_dat->mac_interface);91 return -EINVAL;92 }93 94 val |= GPR_ENET_QOS_CLK_GEN_EN;95 return regmap_update_bits(dwmac->intf_regmap, dwmac->intf_reg_off,96 GPR_ENET_QOS_INTF_MODE_MASK, val);97};98 99static int100imx8dxl_set_intf_mode(struct plat_stmmacenet_data *plat_dat)101{102 int ret = 0;103 104 /* TBD: depends on imx8dxl scu interfaces to be upstreamed */105 return ret;106}107 108static int imx93_set_intf_mode(struct plat_stmmacenet_data *plat_dat)109{110 struct imx_priv_data *dwmac = plat_dat->bsp_priv;111 int val;112 113 switch (plat_dat->mac_interface) {114 case PHY_INTERFACE_MODE_MII:115 val = MX93_GPR_ENET_QOS_INTF_SEL_MII;116 break;117 case PHY_INTERFACE_MODE_RMII:118 val = MX93_GPR_ENET_QOS_INTF_SEL_RMII;119 break;120 case PHY_INTERFACE_MODE_RGMII:121 case PHY_INTERFACE_MODE_RGMII_ID:122 case PHY_INTERFACE_MODE_RGMII_RXID:123 case PHY_INTERFACE_MODE_RGMII_TXID:124 val = MX93_GPR_ENET_QOS_INTF_SEL_RGMII;125 break;126 default:127 dev_dbg(dwmac->dev, "imx dwmac doesn't support %d interface\n",128 plat_dat->mac_interface);129 return -EINVAL;130 }131 132 val |= MX93_GPR_ENET_QOS_CLK_GEN_EN;133 return regmap_update_bits(dwmac->intf_regmap, dwmac->intf_reg_off,134 MX93_GPR_ENET_QOS_INTF_MODE_MASK, val);135};136 137static int imx_dwmac_clks_config(void *priv, bool enabled)138{139 struct imx_priv_data *dwmac = priv;140 int ret = 0;141 142 if (enabled) {143 ret = clk_prepare_enable(dwmac->clk_mem);144 if (ret) {145 dev_err(dwmac->dev, "mem clock enable failed\n");146 return ret;147 }148 149 ret = clk_prepare_enable(dwmac->clk_tx);150 if (ret) {151 dev_err(dwmac->dev, "tx clock enable failed\n");152 clk_disable_unprepare(dwmac->clk_mem);153 return ret;154 }155 } else {156 clk_disable_unprepare(dwmac->clk_tx);157 clk_disable_unprepare(dwmac->clk_mem);158 }159 160 return ret;161}162 163static int imx_dwmac_init(struct platform_device *pdev, void *priv)164{165 struct plat_stmmacenet_data *plat_dat;166 struct imx_priv_data *dwmac = priv;167 int ret;168 169 plat_dat = dwmac->plat_dat;170 171 if (dwmac->ops->set_intf_mode) {172 ret = dwmac->ops->set_intf_mode(plat_dat);173 if (ret)174 return ret;175 }176 177 return 0;178}179 180static void imx_dwmac_exit(struct platform_device *pdev, void *priv)181{182 /* nothing to do now */183}184 185static void imx_dwmac_fix_speed(void *priv, unsigned int speed, unsigned int mode)186{187 struct plat_stmmacenet_data *plat_dat;188 struct imx_priv_data *dwmac = priv;189 unsigned long rate;190 int err;191 192 plat_dat = dwmac->plat_dat;193 194 if (dwmac->ops->mac_rgmii_txclk_auto_adj ||195 (plat_dat->mac_interface == PHY_INTERFACE_MODE_RMII) ||196 (plat_dat->mac_interface == PHY_INTERFACE_MODE_MII))197 return;198 199 switch (speed) {200 case SPEED_1000:201 rate = 125000000;202 break;203 case SPEED_100:204 rate = 25000000;205 break;206 case SPEED_10:207 rate = 2500000;208 break;209 default:210 dev_err(dwmac->dev, "invalid speed %u\n", speed);211 return;212 }213 214 err = clk_set_rate(dwmac->clk_tx, rate);215 if (err < 0)216 dev_err(dwmac->dev, "failed to set tx rate %lu\n", rate);217}218 219static void imx93_dwmac_fix_speed(void *priv, unsigned int speed, unsigned int mode)220{221 struct imx_priv_data *dwmac = priv;222 unsigned int iface;223 int ctrl, old_ctrl;224 225 imx_dwmac_fix_speed(priv, speed, mode);226 227 if (!dwmac || mode != MLO_AN_FIXED)228 return;229 230 if (regmap_read(dwmac->intf_regmap, dwmac->intf_reg_off, &iface))231 return;232 233 iface &= MX93_GPR_ENET_QOS_INTF_MASK;234 if (iface != MX93_GPR_ENET_QOS_INTF_SEL_RGMII)235 return;236 237 old_ctrl = readl(dwmac->base_addr + MAC_CTRL_REG);238 ctrl = old_ctrl & ~CTRL_SPEED_MASK;239 regmap_update_bits(dwmac->intf_regmap, dwmac->intf_reg_off,240 MX93_GPR_ENET_QOS_INTF_MODE_MASK, 0);241 writel(ctrl, dwmac->base_addr + MAC_CTRL_REG);242 243 /* Ensure the settings for CTRL are applied. */244 readl(dwmac->base_addr + MAC_CTRL_REG);245 246 usleep_range(10, 20);247 iface |= MX93_GPR_ENET_QOS_CLK_GEN_EN;248 regmap_update_bits(dwmac->intf_regmap, dwmac->intf_reg_off,249 MX93_GPR_ENET_QOS_INTF_MODE_MASK, iface);250 251 writel(old_ctrl, dwmac->base_addr + MAC_CTRL_REG);252}253 254static int imx_dwmac_mx93_reset(void *priv, void __iomem *ioaddr)255{256 struct plat_stmmacenet_data *plat_dat = priv;257 u32 value = readl(ioaddr + DMA_BUS_MODE);258 259 /* DMA SW reset */260 value |= DMA_BUS_MODE_SFT_RESET;261 writel(value, ioaddr + DMA_BUS_MODE);262 263 if (plat_dat->mac_interface == PHY_INTERFACE_MODE_RMII) {264 usleep_range(100, 200);265 writel(RMII_RESET_SPEED, ioaddr + MAC_CTRL_REG);266 }267 268 return readl_poll_timeout(ioaddr + DMA_BUS_MODE, value,269 !(value & DMA_BUS_MODE_SFT_RESET),270 10000, 1000000);271}272 273static int274imx_dwmac_parse_dt(struct imx_priv_data *dwmac, struct device *dev)275{276 struct device_node *np = dev->of_node;277 int err = 0;278 279 dwmac->rmii_refclk_ext = of_property_read_bool(np, "snps,rmii_refclk_ext");280 281 dwmac->clk_tx = devm_clk_get(dev, "tx");282 if (IS_ERR(dwmac->clk_tx)) {283 dev_err(dev, "failed to get tx clock\n");284 return PTR_ERR(dwmac->clk_tx);285 }286 287 dwmac->clk_mem = NULL;288 289 if (of_machine_is_compatible("fsl,imx8dxl") ||290 of_machine_is_compatible("fsl,imx93")) {291 dwmac->clk_mem = devm_clk_get(dev, "mem");292 if (IS_ERR(dwmac->clk_mem)) {293 dev_err(dev, "failed to get mem clock\n");294 return PTR_ERR(dwmac->clk_mem);295 }296 }297 298 if (of_machine_is_compatible("fsl,imx8mp") ||299 of_machine_is_compatible("fsl,imx93")) {300 /* Binding doc describes the propety:301 * is required by i.MX8MP, i.MX93.302 * is optinoal for i.MX8DXL.303 */304 dwmac->intf_regmap = syscon_regmap_lookup_by_phandle(np, "intf_mode");305 if (IS_ERR(dwmac->intf_regmap))306 return PTR_ERR(dwmac->intf_regmap);307 308 err = of_property_read_u32_index(np, "intf_mode", 1, &dwmac->intf_reg_off);309 if (err) {310 dev_err(dev, "Can't get intf mode reg offset (%d)\n", err);311 return err;312 }313 }314 315 return err;316}317 318static int imx_dwmac_probe(struct platform_device *pdev)319{320 struct plat_stmmacenet_data *plat_dat;321 struct stmmac_resources stmmac_res;322 struct imx_priv_data *dwmac;323 const struct imx_dwmac_ops *data;324 int ret;325 326 ret = stmmac_get_platform_resources(pdev, &stmmac_res);327 if (ret)328 return ret;329 330 dwmac = devm_kzalloc(&pdev->dev, sizeof(*dwmac), GFP_KERNEL);331 if (!dwmac)332 return -ENOMEM;333 334 plat_dat = devm_stmmac_probe_config_dt(pdev, stmmac_res.mac);335 if (IS_ERR(plat_dat))336 return PTR_ERR(plat_dat);337 338 data = of_device_get_match_data(&pdev->dev);339 if (!data) {340 dev_err(&pdev->dev, "failed to get match data\n");341 return -EINVAL;342 }343 344 dwmac->ops = data;345 dwmac->dev = &pdev->dev;346 347 ret = imx_dwmac_parse_dt(dwmac, &pdev->dev);348 if (ret) {349 dev_err(&pdev->dev, "failed to parse OF data\n");350 return ret;351 }352 353 if (data->flags & STMMAC_FLAG_HWTSTAMP_CORRECT_LATENCY)354 plat_dat->flags |= STMMAC_FLAG_HWTSTAMP_CORRECT_LATENCY;355 356 /* Default TX Q0 to use TSO and rest TXQ for TBS */357 for (int i = 1; i < plat_dat->tx_queues_to_use; i++)358 plat_dat->tx_queues_cfg[i].tbs_en = 1;359 360 plat_dat->host_dma_width = dwmac->ops->addr_width;361 plat_dat->init = imx_dwmac_init;362 plat_dat->exit = imx_dwmac_exit;363 plat_dat->clks_config = imx_dwmac_clks_config;364 plat_dat->fix_mac_speed = imx_dwmac_fix_speed;365 plat_dat->bsp_priv = dwmac;366 dwmac->plat_dat = plat_dat;367 dwmac->base_addr = stmmac_res.addr;368 369 ret = imx_dwmac_clks_config(dwmac, true);370 if (ret)371 return ret;372 373 ret = imx_dwmac_init(pdev, dwmac);374 if (ret)375 goto err_dwmac_init;376 377 if (dwmac->ops->fix_mac_speed)378 plat_dat->fix_mac_speed = dwmac->ops->fix_mac_speed;379 dwmac->plat_dat->fix_soc_reset = dwmac->ops->fix_soc_reset;380 381 ret = stmmac_dvr_probe(&pdev->dev, plat_dat, &stmmac_res);382 if (ret)383 goto err_drv_probe;384 385 return 0;386 387err_drv_probe:388 imx_dwmac_exit(pdev, plat_dat->bsp_priv);389err_dwmac_init:390 imx_dwmac_clks_config(dwmac, false);391 return ret;392}393 394static struct imx_dwmac_ops imx8mp_dwmac_data = {395 .addr_width = 34,396 .mac_rgmii_txclk_auto_adj = false,397 .set_intf_mode = imx8mp_set_intf_mode,398 .flags = STMMAC_FLAG_HWTSTAMP_CORRECT_LATENCY,399};400 401static struct imx_dwmac_ops imx8dxl_dwmac_data = {402 .addr_width = 32,403 .mac_rgmii_txclk_auto_adj = true,404 .set_intf_mode = imx8dxl_set_intf_mode,405};406 407static struct imx_dwmac_ops imx93_dwmac_data = {408 .addr_width = 32,409 .mac_rgmii_txclk_auto_adj = true,410 .set_intf_mode = imx93_set_intf_mode,411 .fix_soc_reset = imx_dwmac_mx93_reset,412 .fix_mac_speed = imx93_dwmac_fix_speed,413};414 415static const struct of_device_id imx_dwmac_match[] = {416 { .compatible = "nxp,imx8mp-dwmac-eqos", .data = &imx8mp_dwmac_data },417 { .compatible = "nxp,imx8dxl-dwmac-eqos", .data = &imx8dxl_dwmac_data },418 { .compatible = "nxp,imx93-dwmac-eqos", .data = &imx93_dwmac_data },419 { }420};421MODULE_DEVICE_TABLE(of, imx_dwmac_match);422 423static struct platform_driver imx_dwmac_driver = {424 .probe = imx_dwmac_probe,425 .remove_new = stmmac_pltfr_remove,426 .driver = {427 .name = "imx-dwmac",428 .pm = &stmmac_pltfr_pm_ops,429 .of_match_table = imx_dwmac_match,430 },431};432module_platform_driver(imx_dwmac_driver);433 434MODULE_AUTHOR("NXP");435MODULE_DESCRIPTION("NXP imx8 DWMAC Specific Glue layer");436MODULE_LICENSE("GPL v2");437