File Index
Files and directories
Sign in
FILE

hwif.c

File preview with syntax highlighting.

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