brintos

brintos / linux-shallow public Read only

0
0
Text · 10.6 KiB · 19c93b9 Raw
385 lines · c
1// SPDX-License-Identifier: GPL-2.02/*3 * dwmac-ingenic.c - Ingenic SoCs DWMAC specific glue layer4 *5 * Copyright (c) 2021 周琰杰 (Zhou Yanjie) <zhouyanjie@wanyeetech.com>6 */7 8#include <linux/bitfield.h>9#include <linux/clk.h>10#include <linux/kernel.h>11#include <linux/mfd/syscon.h>12#include <linux/module.h>13#include <linux/of.h>14#include <linux/of_net.h>15#include <linux/phy.h>16#include <linux/platform_device.h>17#include <linux/regmap.h>18#include <linux/slab.h>19#include <linux/stmmac.h>20 21#include "stmmac_platform.h"22 23#define MACPHYC_TXCLK_SEL_MASK		GENMASK(31, 31)24#define MACPHYC_TXCLK_SEL_OUTPUT	0x125#define MACPHYC_TXCLK_SEL_INPUT		0x026#define MACPHYC_MODE_SEL_MASK		GENMASK(31, 31)27#define MACPHYC_MODE_SEL_RMII		0x028#define MACPHYC_TX_SEL_MASK			GENMASK(19, 19)29#define MACPHYC_TX_SEL_ORIGIN		0x030#define MACPHYC_TX_SEL_DELAY		0x131#define MACPHYC_TX_DELAY_MASK		GENMASK(18, 12)32#define MACPHYC_RX_SEL_MASK			GENMASK(11, 11)33#define MACPHYC_RX_SEL_ORIGIN		0x034#define MACPHYC_RX_SEL_DELAY		0x135#define MACPHYC_RX_DELAY_MASK		GENMASK(10, 4)36#define MACPHYC_SOFT_RST_MASK		GENMASK(3, 3)37#define MACPHYC_PHY_INFT_MASK		GENMASK(2, 0)38#define MACPHYC_PHY_INFT_RMII		0x439#define MACPHYC_PHY_INFT_RGMII		0x140#define MACPHYC_PHY_INFT_GMII		0x041#define MACPHYC_PHY_INFT_MII		0x042 43#define MACPHYC_TX_DELAY_PS_MAX		249644#define MACPHYC_TX_DELAY_PS_MIN		2045 46#define MACPHYC_RX_DELAY_PS_MAX		249647#define MACPHYC_RX_DELAY_PS_MIN		2048 49enum ingenic_mac_version {50	ID_JZ4775,51	ID_X1000,52	ID_X1600,53	ID_X1830,54	ID_X2000,55};56 57struct ingenic_mac {58	const struct ingenic_soc_info *soc_info;59	struct device *dev;60	struct regmap *regmap;61 62	int rx_delay;63	int tx_delay;64};65 66struct ingenic_soc_info {67	enum ingenic_mac_version version;68	u32 mask;69 70	int (*set_mode)(struct plat_stmmacenet_data *plat_dat);71};72 73static int ingenic_mac_init(struct plat_stmmacenet_data *plat_dat)74{75	struct ingenic_mac *mac = plat_dat->bsp_priv;76	int ret;77 78	if (mac->soc_info->set_mode) {79		ret = mac->soc_info->set_mode(plat_dat);80		if (ret)81			return ret;82	}83 84	return 0;85}86 87static int jz4775_mac_set_mode(struct plat_stmmacenet_data *plat_dat)88{89	struct ingenic_mac *mac = plat_dat->bsp_priv;90	unsigned int val;91 92	switch (plat_dat->mac_interface) {93	case PHY_INTERFACE_MODE_MII:94		val = FIELD_PREP(MACPHYC_TXCLK_SEL_MASK, MACPHYC_TXCLK_SEL_INPUT) |95			  FIELD_PREP(MACPHYC_PHY_INFT_MASK, MACPHYC_PHY_INFT_MII);96		dev_dbg(mac->dev, "MAC PHY Control Register: PHY_INTERFACE_MODE_MII\n");97		break;98 99	case PHY_INTERFACE_MODE_GMII:100		val = FIELD_PREP(MACPHYC_TXCLK_SEL_MASK, MACPHYC_TXCLK_SEL_INPUT) |101			  FIELD_PREP(MACPHYC_PHY_INFT_MASK, MACPHYC_PHY_INFT_GMII);102		dev_dbg(mac->dev, "MAC PHY Control Register: PHY_INTERFACE_MODE_GMII\n");103		break;104 105	case PHY_INTERFACE_MODE_RMII:106		val = FIELD_PREP(MACPHYC_TXCLK_SEL_MASK, MACPHYC_TXCLK_SEL_INPUT) |107			  FIELD_PREP(MACPHYC_PHY_INFT_MASK, MACPHYC_PHY_INFT_RMII);108		dev_dbg(mac->dev, "MAC PHY Control Register: PHY_INTERFACE_MODE_RMII\n");109		break;110 111	case PHY_INTERFACE_MODE_RGMII:112	case PHY_INTERFACE_MODE_RGMII_ID:113	case PHY_INTERFACE_MODE_RGMII_TXID:114	case PHY_INTERFACE_MODE_RGMII_RXID:115		val = FIELD_PREP(MACPHYC_TXCLK_SEL_MASK, MACPHYC_TXCLK_SEL_INPUT) |116			  FIELD_PREP(MACPHYC_PHY_INFT_MASK, MACPHYC_PHY_INFT_RGMII);117		dev_dbg(mac->dev, "MAC PHY Control Register: PHY_INTERFACE_MODE_RGMII\n");118		break;119 120	default:121		dev_err(mac->dev, "Unsupported interface %d", plat_dat->mac_interface);122		return -EINVAL;123	}124 125	/* Update MAC PHY control register */126	return regmap_update_bits(mac->regmap, 0, mac->soc_info->mask, val);127}128 129static int x1000_mac_set_mode(struct plat_stmmacenet_data *plat_dat)130{131	struct ingenic_mac *mac = plat_dat->bsp_priv;132 133	switch (plat_dat->mac_interface) {134	case PHY_INTERFACE_MODE_RMII:135		dev_dbg(mac->dev, "MAC PHY Control Register: PHY_INTERFACE_MODE_RMII\n");136		break;137 138	default:139		dev_err(mac->dev, "Unsupported interface %d", plat_dat->mac_interface);140		return -EINVAL;141	}142 143	/* Update MAC PHY control register */144	return regmap_update_bits(mac->regmap, 0, mac->soc_info->mask, 0);145}146 147static int x1600_mac_set_mode(struct plat_stmmacenet_data *plat_dat)148{149	struct ingenic_mac *mac = plat_dat->bsp_priv;150	unsigned int val;151 152	switch (plat_dat->mac_interface) {153	case PHY_INTERFACE_MODE_RMII:154		val = FIELD_PREP(MACPHYC_PHY_INFT_MASK, MACPHYC_PHY_INFT_RMII);155		dev_dbg(mac->dev, "MAC PHY Control Register: PHY_INTERFACE_MODE_RMII\n");156		break;157 158	default:159		dev_err(mac->dev, "Unsupported interface %d", plat_dat->mac_interface);160		return -EINVAL;161	}162 163	/* Update MAC PHY control register */164	return regmap_update_bits(mac->regmap, 0, mac->soc_info->mask, val);165}166 167static int x1830_mac_set_mode(struct plat_stmmacenet_data *plat_dat)168{169	struct ingenic_mac *mac = plat_dat->bsp_priv;170	unsigned int val;171 172	switch (plat_dat->mac_interface) {173	case PHY_INTERFACE_MODE_RMII:174		val = FIELD_PREP(MACPHYC_MODE_SEL_MASK, MACPHYC_MODE_SEL_RMII) |175			  FIELD_PREP(MACPHYC_PHY_INFT_MASK, MACPHYC_PHY_INFT_RMII);176		dev_dbg(mac->dev, "MAC PHY Control Register: PHY_INTERFACE_MODE_RMII\n");177		break;178 179	default:180		dev_err(mac->dev, "Unsupported interface %d", plat_dat->mac_interface);181		return -EINVAL;182	}183 184	/* Update MAC PHY control register */185	return regmap_update_bits(mac->regmap, 0, mac->soc_info->mask, val);186}187 188static int x2000_mac_set_mode(struct plat_stmmacenet_data *plat_dat)189{190	struct ingenic_mac *mac = plat_dat->bsp_priv;191	unsigned int val;192 193	switch (plat_dat->mac_interface) {194	case PHY_INTERFACE_MODE_RMII:195		val = FIELD_PREP(MACPHYC_TX_SEL_MASK, MACPHYC_TX_SEL_ORIGIN) |196			  FIELD_PREP(MACPHYC_RX_SEL_MASK, MACPHYC_RX_SEL_ORIGIN) |197			  FIELD_PREP(MACPHYC_PHY_INFT_MASK, MACPHYC_PHY_INFT_RMII);198		dev_dbg(mac->dev, "MAC PHY Control Register: PHY_INTERFACE_MODE_RMII\n");199		break;200 201	case PHY_INTERFACE_MODE_RGMII:202	case PHY_INTERFACE_MODE_RGMII_ID:203	case PHY_INTERFACE_MODE_RGMII_TXID:204	case PHY_INTERFACE_MODE_RGMII_RXID:205		val = FIELD_PREP(MACPHYC_PHY_INFT_MASK, MACPHYC_PHY_INFT_RGMII);206 207		if (mac->tx_delay == 0)208			val |= FIELD_PREP(MACPHYC_TX_SEL_MASK, MACPHYC_TX_SEL_ORIGIN);209		else210			val |= FIELD_PREP(MACPHYC_TX_SEL_MASK, MACPHYC_TX_SEL_DELAY) |211				   FIELD_PREP(MACPHYC_TX_DELAY_MASK, (mac->tx_delay + 9750) / 19500 - 1);212 213		if (mac->rx_delay == 0)214			val |= FIELD_PREP(MACPHYC_RX_SEL_MASK, MACPHYC_RX_SEL_ORIGIN);215		else216			val |= FIELD_PREP(MACPHYC_RX_SEL_MASK, MACPHYC_RX_SEL_DELAY) |217				   FIELD_PREP(MACPHYC_RX_DELAY_MASK, (mac->rx_delay + 9750) / 19500 - 1);218 219		dev_dbg(mac->dev, "MAC PHY Control Register: PHY_INTERFACE_MODE_RGMII\n");220		break;221 222	default:223		dev_err(mac->dev, "Unsupported interface %d", plat_dat->mac_interface);224		return -EINVAL;225	}226 227	/* Update MAC PHY control register */228	return regmap_update_bits(mac->regmap, 0, mac->soc_info->mask, val);229}230 231static int ingenic_mac_probe(struct platform_device *pdev)232{233	struct plat_stmmacenet_data *plat_dat;234	struct stmmac_resources stmmac_res;235	struct ingenic_mac *mac;236	const struct ingenic_soc_info *data;237	u32 tx_delay_ps, rx_delay_ps;238	int ret;239 240	ret = stmmac_get_platform_resources(pdev, &stmmac_res);241	if (ret)242		return ret;243 244	plat_dat = devm_stmmac_probe_config_dt(pdev, stmmac_res.mac);245	if (IS_ERR(plat_dat))246		return PTR_ERR(plat_dat);247 248	mac = devm_kzalloc(&pdev->dev, sizeof(*mac), GFP_KERNEL);249	if (!mac)250		return -ENOMEM;251 252	data = of_device_get_match_data(&pdev->dev);253	if (!data) {254		dev_err(&pdev->dev, "No of match data provided\n");255		return -EINVAL;256	}257 258	/* Get MAC PHY control register */259	mac->regmap = syscon_regmap_lookup_by_phandle(pdev->dev.of_node, "mode-reg");260	if (IS_ERR(mac->regmap)) {261		dev_err(&pdev->dev, "%s: Failed to get syscon regmap\n", __func__);262		return PTR_ERR(mac->regmap);263	}264 265	if (!of_property_read_u32(pdev->dev.of_node, "tx-clk-delay-ps", &tx_delay_ps)) {266		if (tx_delay_ps >= MACPHYC_TX_DELAY_PS_MIN &&267			tx_delay_ps <= MACPHYC_TX_DELAY_PS_MAX) {268			mac->tx_delay = tx_delay_ps * 1000;269		} else {270			dev_err(&pdev->dev, "Invalid TX clock delay: %dps\n", tx_delay_ps);271			return -EINVAL;272		}273	}274 275	if (!of_property_read_u32(pdev->dev.of_node, "rx-clk-delay-ps", &rx_delay_ps)) {276		if (rx_delay_ps >= MACPHYC_RX_DELAY_PS_MIN &&277			rx_delay_ps <= MACPHYC_RX_DELAY_PS_MAX) {278			mac->rx_delay = rx_delay_ps * 1000;279		} else {280			dev_err(&pdev->dev, "Invalid RX clock delay: %dps\n", rx_delay_ps);281			return -EINVAL;282		}283	}284 285	mac->soc_info = data;286	mac->dev = &pdev->dev;287 288	plat_dat->bsp_priv = mac;289 290	ret = ingenic_mac_init(plat_dat);291	if (ret)292		return ret;293 294	return stmmac_dvr_probe(&pdev->dev, plat_dat, &stmmac_res);295}296 297#ifdef CONFIG_PM_SLEEP298static int ingenic_mac_suspend(struct device *dev)299{300	int ret;301 302	ret = stmmac_suspend(dev);303 304	return ret;305}306 307static int ingenic_mac_resume(struct device *dev)308{309	struct net_device *ndev = dev_get_drvdata(dev);310	struct stmmac_priv *priv = netdev_priv(ndev);311	int ret;312 313	ret = ingenic_mac_init(priv->plat);314	if (ret)315		return ret;316 317	ret = stmmac_resume(dev);318 319	return ret;320}321#endif /* CONFIG_PM_SLEEP */322 323static SIMPLE_DEV_PM_OPS(ingenic_mac_pm_ops, ingenic_mac_suspend, ingenic_mac_resume);324 325static struct ingenic_soc_info jz4775_soc_info = {326	.version = ID_JZ4775,327	.mask = MACPHYC_TXCLK_SEL_MASK | MACPHYC_SOFT_RST_MASK | MACPHYC_PHY_INFT_MASK,328 329	.set_mode = jz4775_mac_set_mode,330};331 332static struct ingenic_soc_info x1000_soc_info = {333	.version = ID_X1000,334	.mask = MACPHYC_SOFT_RST_MASK,335 336	.set_mode = x1000_mac_set_mode,337};338 339static struct ingenic_soc_info x1600_soc_info = {340	.version = ID_X1600,341	.mask = MACPHYC_SOFT_RST_MASK | MACPHYC_PHY_INFT_MASK,342 343	.set_mode = x1600_mac_set_mode,344};345 346static struct ingenic_soc_info x1830_soc_info = {347	.version = ID_X1830,348	.mask = MACPHYC_MODE_SEL_MASK | MACPHYC_SOFT_RST_MASK | MACPHYC_PHY_INFT_MASK,349 350	.set_mode = x1830_mac_set_mode,351};352 353static struct ingenic_soc_info x2000_soc_info = {354	.version = ID_X2000,355	.mask = MACPHYC_TX_SEL_MASK | MACPHYC_TX_DELAY_MASK | MACPHYC_RX_SEL_MASK |356			MACPHYC_RX_DELAY_MASK | MACPHYC_SOFT_RST_MASK | MACPHYC_PHY_INFT_MASK,357 358	.set_mode = x2000_mac_set_mode,359};360 361static const struct of_device_id ingenic_mac_of_matches[] = {362	{ .compatible = "ingenic,jz4775-mac", .data = &jz4775_soc_info },363	{ .compatible = "ingenic,x1000-mac", .data = &x1000_soc_info },364	{ .compatible = "ingenic,x1600-mac", .data = &x1600_soc_info },365	{ .compatible = "ingenic,x1830-mac", .data = &x1830_soc_info },366	{ .compatible = "ingenic,x2000-mac", .data = &x2000_soc_info },367	{ }368};369MODULE_DEVICE_TABLE(of, ingenic_mac_of_matches);370 371static struct platform_driver ingenic_mac_driver = {372	.probe		= ingenic_mac_probe,373	.remove_new	= stmmac_pltfr_remove,374	.driver		= {375		.name	= "ingenic-mac",376		.pm		= pm_ptr(&ingenic_mac_pm_ops),377		.of_match_table = ingenic_mac_of_matches,378	},379};380module_platform_driver(ingenic_mac_driver);381 382MODULE_AUTHOR("周琰杰 (Zhou Yanjie) <zhouyanjie@wanyeetech.com>");383MODULE_DESCRIPTION("Ingenic SoCs DWMAC specific glue layer");384MODULE_LICENSE("GPL v2");385