brintos

brintos / linux-shallow public Read only

0
0
Text · 11.0 KiB · 6b65420 Raw
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