brintos

brintos / linux-shallow public Read only

0
0
Text · 8.7 KiB · 88cce28 Raw
377 lines · c
1// SPDX-License-Identifier: (GPL-2.0 OR MIT)2/*3 * Copyright (c) 2018 Synopsys, Inc. and/or its affiliates.4 * stmmac HW Interface Handling5 */6 7#include "common.h"8#include "stmmac.h"9#include "stmmac_ptp.h"10#include "stmmac_est.h"11 12static u32 stmmac_get_id(struct stmmac_priv *priv, u32 id_reg)13{14	u32 reg = readl(priv->ioaddr + id_reg);15 16	if (!reg) {17		dev_info(priv->device, "Version ID not available\n");18		return 0x0;19	}20 21	dev_info(priv->device, "User ID: 0x%x, Synopsys ID: 0x%x\n",22			(unsigned int)(reg & GENMASK(15, 8)) >> 8,23			(unsigned int)(reg & GENMASK(7, 0)));24	return reg & GENMASK(7, 0);25}26 27static u32 stmmac_get_dev_id(struct stmmac_priv *priv, u32 id_reg)28{29	u32 reg = readl(priv->ioaddr + id_reg);30 31	if (!reg) {32		dev_info(priv->device, "Version ID not available\n");33		return 0x0;34	}35 36	return (reg & GENMASK(15, 8)) >> 8;37}38 39static void stmmac_dwmac_mode_quirk(struct stmmac_priv *priv)40{41	struct mac_device_info *mac = priv->hw;42 43	if (priv->chain_mode) {44		dev_info(priv->device, "Chain mode enabled\n");45		priv->mode = STMMAC_CHAIN_MODE;46		mac->mode = &chain_mode_ops;47	} else {48		dev_info(priv->device, "Ring mode enabled\n");49		priv->mode = STMMAC_RING_MODE;50		mac->mode = &ring_mode_ops;51	}52}53 54static int stmmac_dwmac1_quirks(struct stmmac_priv *priv)55{56	struct mac_device_info *mac = priv->hw;57 58	if (priv->plat->enh_desc) {59		dev_info(priv->device, "Enhanced/Alternate descriptors\n");60 61		/* GMAC older than 3.50 has no extended descriptors */62		if (priv->synopsys_id >= DWMAC_CORE_3_50) {63			dev_info(priv->device, "Enabled extended descriptors\n");64			priv->extend_desc = 1;65		} else {66			dev_warn(priv->device, "Extended descriptors not supported\n");67		}68 69		mac->desc = &enh_desc_ops;70	} else {71		dev_info(priv->device, "Normal descriptors\n");72		mac->desc = &ndesc_ops;73	}74 75	stmmac_dwmac_mode_quirk(priv);76	return 0;77}78 79static int stmmac_dwmac4_quirks(struct stmmac_priv *priv)80{81	stmmac_dwmac_mode_quirk(priv);82	return 0;83}84 85static int stmmac_dwxlgmac_quirks(struct stmmac_priv *priv)86{87	priv->hw->xlgmac = true;88	return 0;89}90 91int stmmac_reset(struct stmmac_priv *priv, void __iomem *ioaddr)92{93	struct plat_stmmacenet_data *plat = priv ? priv->plat : NULL;94 95	if (!priv)96		return -EINVAL;97 98	if (plat && plat->fix_soc_reset)99		return plat->fix_soc_reset(plat, ioaddr);100 101	return stmmac_do_callback(priv, dma, reset, ioaddr);102}103 104static const struct stmmac_hwif_entry {105	bool gmac;106	bool gmac4;107	bool xgmac;108	u32 min_id;109	u32 dev_id;110	const struct stmmac_regs_off regs;111	const void *desc;112	const void *dma;113	const void *mac;114	const void *hwtimestamp;115	const void *mode;116	const void *tc;117	const void *mmc;118	const void *est;119	int (*setup)(struct stmmac_priv *priv);120	int (*quirks)(struct stmmac_priv *priv);121} stmmac_hw[] = {122	/* NOTE: New HW versions shall go to the end of this table */123	{124		.gmac = false,125		.gmac4 = false,126		.xgmac = false,127		.min_id = 0,128		.regs = {129			.ptp_off = PTP_GMAC3_X_OFFSET,130			.mmc_off = MMC_GMAC3_X_OFFSET,131		},132		.desc = NULL,133		.dma = &dwmac100_dma_ops,134		.mac = &dwmac100_ops,135		.hwtimestamp = &stmmac_ptp,136		.mode = NULL,137		.tc = NULL,138		.mmc = &dwmac_mmc_ops,139		.setup = dwmac100_setup,140		.quirks = stmmac_dwmac1_quirks,141	}, {142		.gmac = true,143		.gmac4 = false,144		.xgmac = false,145		.min_id = 0,146		.regs = {147			.ptp_off = PTP_GMAC3_X_OFFSET,148			.mmc_off = MMC_GMAC3_X_OFFSET,149		},150		.desc = NULL,151		.dma = &dwmac1000_dma_ops,152		.mac = &dwmac1000_ops,153		.hwtimestamp = &stmmac_ptp,154		.mode = NULL,155		.tc = NULL,156		.mmc = &dwmac_mmc_ops,157		.setup = dwmac1000_setup,158		.quirks = stmmac_dwmac1_quirks,159	}, {160		.gmac = false,161		.gmac4 = true,162		.xgmac = false,163		.min_id = 0,164		.regs = {165			.ptp_off = PTP_GMAC4_OFFSET,166			.mmc_off = MMC_GMAC4_OFFSET,167			.est_off = EST_GMAC4_OFFSET,168		},169		.desc = &dwmac4_desc_ops,170		.dma = &dwmac4_dma_ops,171		.mac = &dwmac4_ops,172		.hwtimestamp = &stmmac_ptp,173		.mode = NULL,174		.tc = &dwmac4_tc_ops,175		.mmc = &dwmac_mmc_ops,176		.est = &dwmac510_est_ops,177		.setup = dwmac4_setup,178		.quirks = stmmac_dwmac4_quirks,179	}, {180		.gmac = false,181		.gmac4 = true,182		.xgmac = false,183		.min_id = DWMAC_CORE_4_00,184		.regs = {185			.ptp_off = PTP_GMAC4_OFFSET,186			.mmc_off = MMC_GMAC4_OFFSET,187			.est_off = EST_GMAC4_OFFSET,188		},189		.desc = &dwmac4_desc_ops,190		.dma = &dwmac4_dma_ops,191		.mac = &dwmac410_ops,192		.hwtimestamp = &stmmac_ptp,193		.mode = &dwmac4_ring_mode_ops,194		.tc = &dwmac510_tc_ops,195		.mmc = &dwmac_mmc_ops,196		.est = &dwmac510_est_ops,197		.setup = dwmac4_setup,198		.quirks = NULL,199	}, {200		.gmac = false,201		.gmac4 = true,202		.xgmac = false,203		.min_id = DWMAC_CORE_4_10,204		.regs = {205			.ptp_off = PTP_GMAC4_OFFSET,206			.mmc_off = MMC_GMAC4_OFFSET,207			.est_off = EST_GMAC4_OFFSET,208		},209		.desc = &dwmac4_desc_ops,210		.dma = &dwmac410_dma_ops,211		.mac = &dwmac410_ops,212		.hwtimestamp = &stmmac_ptp,213		.mode = &dwmac4_ring_mode_ops,214		.tc = &dwmac510_tc_ops,215		.mmc = &dwmac_mmc_ops,216		.est = &dwmac510_est_ops,217		.setup = dwmac4_setup,218		.quirks = NULL,219	}, {220		.gmac = false,221		.gmac4 = true,222		.xgmac = false,223		.min_id = DWMAC_CORE_5_10,224		.regs = {225			.ptp_off = PTP_GMAC4_OFFSET,226			.mmc_off = MMC_GMAC4_OFFSET,227			.est_off = EST_GMAC4_OFFSET,228		},229		.desc = &dwmac4_desc_ops,230		.dma = &dwmac410_dma_ops,231		.mac = &dwmac510_ops,232		.hwtimestamp = &stmmac_ptp,233		.mode = &dwmac4_ring_mode_ops,234		.tc = &dwmac510_tc_ops,235		.mmc = &dwmac_mmc_ops,236		.est = &dwmac510_est_ops,237		.setup = dwmac4_setup,238		.quirks = NULL,239	}, {240		.gmac = false,241		.gmac4 = false,242		.xgmac = true,243		.min_id = DWXGMAC_CORE_2_10,244		.dev_id = DWXGMAC_ID,245		.regs = {246			.ptp_off = PTP_XGMAC_OFFSET,247			.mmc_off = MMC_XGMAC_OFFSET,248			.est_off = EST_XGMAC_OFFSET,249		},250		.desc = &dwxgmac210_desc_ops,251		.dma = &dwxgmac210_dma_ops,252		.mac = &dwxgmac210_ops,253		.hwtimestamp = &stmmac_ptp,254		.mode = NULL,255		.tc = &dwxgmac_tc_ops,256		.mmc = &dwxgmac_mmc_ops,257		.est = &dwmac510_est_ops,258		.setup = dwxgmac2_setup,259		.quirks = NULL,260	}, {261		.gmac = false,262		.gmac4 = false,263		.xgmac = true,264		.min_id = DWXLGMAC_CORE_2_00,265		.dev_id = DWXLGMAC_ID,266		.regs = {267			.ptp_off = PTP_XGMAC_OFFSET,268			.mmc_off = MMC_XGMAC_OFFSET,269			.est_off = EST_XGMAC_OFFSET,270		},271		.desc = &dwxgmac210_desc_ops,272		.dma = &dwxgmac210_dma_ops,273		.mac = &dwxlgmac2_ops,274		.hwtimestamp = &stmmac_ptp,275		.mode = NULL,276		.tc = &dwxgmac_tc_ops,277		.mmc = &dwxgmac_mmc_ops,278		.est = &dwmac510_est_ops,279		.setup = dwxlgmac2_setup,280		.quirks = stmmac_dwxlgmac_quirks,281	},282};283 284int stmmac_hwif_init(struct stmmac_priv *priv)285{286	bool needs_xgmac = priv->plat->has_xgmac;287	bool needs_gmac4 = priv->plat->has_gmac4;288	bool needs_gmac = priv->plat->has_gmac;289	const struct stmmac_hwif_entry *entry;290	struct mac_device_info *mac;291	bool needs_setup = true;292	u32 id, dev_id = 0;293	int i, ret;294 295	if (needs_gmac) {296		id = stmmac_get_id(priv, GMAC_VERSION);297	} else if (needs_gmac4 || needs_xgmac) {298		id = stmmac_get_id(priv, GMAC4_VERSION);299		if (needs_xgmac)300			dev_id = stmmac_get_dev_id(priv, GMAC4_VERSION);301	} else {302		id = 0;303	}304 305	/* Save ID for later use */306	priv->synopsys_id = id;307 308	/* Lets assume some safe values first */309	priv->ptpaddr = priv->ioaddr +310		(needs_gmac4 ? PTP_GMAC4_OFFSET : PTP_GMAC3_X_OFFSET);311	priv->mmcaddr = priv->ioaddr +312		(needs_gmac4 ? MMC_GMAC4_OFFSET : MMC_GMAC3_X_OFFSET);313	if (needs_gmac4)314		priv->estaddr = priv->ioaddr + EST_GMAC4_OFFSET;315	else if (needs_xgmac)316		priv->estaddr = priv->ioaddr + EST_XGMAC_OFFSET;317 318	/* Check for HW specific setup first */319	if (priv->plat->setup) {320		mac = priv->plat->setup(priv);321		needs_setup = false;322	} else {323		mac = devm_kzalloc(priv->device, sizeof(*mac), GFP_KERNEL);324	}325 326	if (!mac)327		return -ENOMEM;328 329	/* Fallback to generic HW */330	for (i = ARRAY_SIZE(stmmac_hw) - 1; i >= 0; i--) {331		entry = &stmmac_hw[i];332 333		if (needs_gmac ^ entry->gmac)334			continue;335		if (needs_gmac4 ^ entry->gmac4)336			continue;337		if (needs_xgmac ^ entry->xgmac)338			continue;339		/* Use synopsys_id var because some setups can override this */340		if (priv->synopsys_id < entry->min_id)341			continue;342		if (needs_xgmac && (dev_id ^ entry->dev_id))343			continue;344 345		/* Only use generic HW helpers if needed */346		mac->desc = mac->desc ? : entry->desc;347		mac->dma = mac->dma ? : entry->dma;348		mac->mac = mac->mac ? : entry->mac;349		mac->ptp = mac->ptp ? : entry->hwtimestamp;350		mac->mode = mac->mode ? : entry->mode;351		mac->tc = mac->tc ? : entry->tc;352		mac->mmc = mac->mmc ? : entry->mmc;353		mac->est = mac->est ? : entry->est;354 355		priv->hw = mac;356		priv->ptpaddr = priv->ioaddr + entry->regs.ptp_off;357		priv->mmcaddr = priv->ioaddr + entry->regs.mmc_off;358		if (entry->est)359			priv->estaddr = priv->ioaddr + entry->regs.est_off;360 361		/* Entry found */362		if (needs_setup) {363			ret = entry->setup(priv);364			if (ret)365				return ret;366		}367 368		/* Save quirks, if needed for posterior use */369		priv->hwif_quirks = entry->quirks;370		return 0;371	}372 373	dev_err(priv->device, "Failed to find HW IF (id=0x%x, gmac=%d/%d)\n",374			id, needs_gmac, needs_gmac4);375	return -EINVAL;376}377