xref: /linux/drivers/net/ethernet/stmicro/stmmac/hwif.c (revision d30c1683aaecb93d2ab95685dc4300a33d3cea7a)
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 
16 struct stmmac_version {
17 	u8 snpsver;
18 	u8 dev_id;
19 };
20 
21 static 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 
54 static 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 
69 static 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 
94 static int stmmac_dwmac4_quirks(struct stmmac_priv *priv)
95 {
96 	stmmac_dwmac_mode_quirk(priv);
97 	return 0;
98 }
99 
100 static int stmmac_dwxlgmac_quirks(struct stmmac_priv *priv)
101 {
102 	priv->hw->xlgmac = true;
103 	return 0;
104 }
105 
106 int 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 
117 static 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 
300 static const struct stmmac_hwif_entry *
301 stmmac_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 
324 int 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 }
411