xref: /linux/drivers/net/ethernet/stmicro/stmmac/hwif.c (revision 91ec2035134982b98fab0609a9fd8480e8217dc1)
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 
stmmac_get_version(struct stmmac_priv * priv,struct stmmac_version * ver)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 
stmmac_dwmac_mode_quirk(struct stmmac_priv * priv)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->descriptor_mode = STMMAC_CHAIN_MODE;
61 		mac->mode = &chain_mode_ops;
62 	} else {
63 		dev_info(priv->device, "Ring mode enabled\n");
64 		priv->descriptor_mode = STMMAC_RING_MODE;
65 		mac->mode = &ring_mode_ops;
66 	}
67 }
68 
stmmac_dwmac1_quirks(struct stmmac_priv * priv)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 = true;
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 
stmmac_dwmac4_quirks(struct stmmac_priv * priv)94 static int stmmac_dwmac4_quirks(struct stmmac_priv *priv)
95 {
96 	stmmac_dwmac_mode_quirk(priv);
97 	return 0;
98 }
99 
stmmac_reset(struct stmmac_priv * priv)100 int stmmac_reset(struct stmmac_priv *priv)
101 {
102 	struct plat_stmmacenet_data *plat = priv->plat;
103 	void __iomem *ioaddr = priv->ioaddr;
104 
105 	if (plat && plat->fix_soc_reset)
106 		return plat->fix_soc_reset(priv);
107 
108 	return stmmac_do_callback(priv, dma, reset, ioaddr);
109 }
110 
111 static const struct stmmac_hwif_entry {
112 	enum dwmac_core_type core_type;
113 	u32 min_id;
114 	u32 dev_id;
115 	const struct stmmac_regs_off regs;
116 	const void *desc;
117 	const void *dma;
118 	const void *mac;
119 	const void *hwtimestamp;
120 	const void *ptp;
121 	const void *mode;
122 	const void *tc;
123 	const void *mmc;
124 	const void *est;
125 	const void *vlan;
126 	int (*setup)(struct stmmac_priv *priv);
127 	int (*quirks)(struct stmmac_priv *priv);
128 } stmmac_hw[] = {
129 	/* NOTE: New HW versions shall go to the end of this table */
130 	{
131 		.core_type = DWMAC_CORE_MAC100,
132 		.min_id = 0,
133 		.regs = {
134 			.ptp_off = PTP_GMAC3_X_OFFSET,
135 			.mmc_off = MMC_GMAC3_X_OFFSET,
136 		},
137 		.desc = NULL,
138 		.dma = &dwmac100_dma_ops,
139 		.mac = &dwmac100_ops,
140 		.hwtimestamp = &dwmac1000_ptp,
141 		.ptp = &dwmac1000_ptp_clock_ops,
142 		.mode = NULL,
143 		.tc = NULL,
144 		.mmc = &dwmac_mmc_ops,
145 		.setup = dwmac100_setup,
146 		.quirks = stmmac_dwmac1_quirks,
147 	}, {
148 		.core_type = DWMAC_CORE_GMAC,
149 		.min_id = 0,
150 		.regs = {
151 			.ptp_off = PTP_GMAC3_X_OFFSET,
152 			.mmc_off = MMC_GMAC3_X_OFFSET,
153 		},
154 		.desc = NULL,
155 		.dma = &dwmac1000_dma_ops,
156 		.mac = &dwmac1000_ops,
157 		.hwtimestamp = &dwmac1000_ptp,
158 		.ptp = &dwmac1000_ptp_clock_ops,
159 		.mode = NULL,
160 		.tc = NULL,
161 		.mmc = &dwmac_mmc_ops,
162 		.setup = dwmac1000_setup,
163 		.quirks = stmmac_dwmac1_quirks,
164 	}, {
165 		.core_type = DWMAC_CORE_GMAC4,
166 		.min_id = 0,
167 		.regs = {
168 			.ptp_off = PTP_GMAC4_OFFSET,
169 			.mmc_off = MMC_GMAC4_OFFSET,
170 			.est_off = EST_GMAC4_OFFSET,
171 		},
172 		.desc = &dwmac4_desc_ops,
173 		.dma = &dwmac4_dma_ops,
174 		.mac = &dwmac4_ops,
175 		.vlan = &dwmac_vlan_ops,
176 		.hwtimestamp = &stmmac_ptp,
177 		.ptp = &stmmac_ptp_clock_ops,
178 		.mode = NULL,
179 		.tc = &dwmac4_tc_ops,
180 		.mmc = &dwmac_mmc_ops,
181 		.est = &dwmac510_est_ops,
182 		.setup = dwmac4_setup,
183 		.quirks = stmmac_dwmac4_quirks,
184 	}, {
185 		.core_type = DWMAC_CORE_GMAC4,
186 		.min_id = DWMAC_CORE_4_00,
187 		.regs = {
188 			.ptp_off = PTP_GMAC4_OFFSET,
189 			.mmc_off = MMC_GMAC4_OFFSET,
190 			.est_off = EST_GMAC4_OFFSET,
191 			.fpe_reg = &dwmac5_fpe_reg,
192 		},
193 		.desc = &dwmac4_desc_ops,
194 		.dma = &dwmac4_dma_ops,
195 		.mac = &dwmac410_ops,
196 		.vlan = &dwmac_vlan_ops,
197 		.hwtimestamp = &stmmac_ptp,
198 		.ptp = &stmmac_ptp_clock_ops,
199 		.mode = &dwmac4_ring_mode_ops,
200 		.tc = &dwmac510_tc_ops,
201 		.mmc = &dwmac_mmc_ops,
202 		.est = &dwmac510_est_ops,
203 		.setup = dwmac4_setup,
204 		.quirks = NULL,
205 	}, {
206 		.core_type = DWMAC_CORE_GMAC4,
207 		.min_id = DWMAC_CORE_4_10,
208 		.regs = {
209 			.ptp_off = PTP_GMAC4_OFFSET,
210 			.mmc_off = MMC_GMAC4_OFFSET,
211 			.est_off = EST_GMAC4_OFFSET,
212 			.fpe_reg = &dwmac5_fpe_reg,
213 		},
214 		.desc = &dwmac4_desc_ops,
215 		.dma = &dwmac410_dma_ops,
216 		.mac = &dwmac410_ops,
217 		.vlan = &dwmac_vlan_ops,
218 		.hwtimestamp = &stmmac_ptp,
219 		.ptp = &stmmac_ptp_clock_ops,
220 		.mode = &dwmac4_ring_mode_ops,
221 		.tc = &dwmac510_tc_ops,
222 		.mmc = &dwmac_mmc_ops,
223 		.est = &dwmac510_est_ops,
224 		.setup = dwmac4_setup,
225 		.quirks = NULL,
226 	}, {
227 		.core_type = DWMAC_CORE_GMAC4,
228 		.min_id = DWMAC_CORE_5_10,
229 		.regs = {
230 			.ptp_off = PTP_GMAC4_OFFSET,
231 			.mmc_off = MMC_GMAC4_OFFSET,
232 			.est_off = EST_GMAC4_OFFSET,
233 			.fpe_reg = &dwmac5_fpe_reg,
234 		},
235 		.desc = &dwmac4_desc_ops,
236 		.dma = &dwmac410_dma_ops,
237 		.mac = &dwmac510_ops,
238 		.vlan = &dwmac_vlan_ops,
239 		.hwtimestamp = &stmmac_ptp,
240 		.ptp = &stmmac_ptp_clock_ops,
241 		.mode = &dwmac4_ring_mode_ops,
242 		.tc = &dwmac510_tc_ops,
243 		.mmc = &dwmac_mmc_ops,
244 		.est = &dwmac510_est_ops,
245 		.setup = dwmac4_setup,
246 		.quirks = NULL,
247 	}, {
248 		.core_type = DWMAC_CORE_XGMAC,
249 		.min_id = DWXGMAC_CORE_2_10,
250 		.dev_id = DWXGMAC_ID,
251 		.regs = {
252 			.ptp_off = PTP_XGMAC_OFFSET,
253 			.mmc_off = MMC_XGMAC_OFFSET,
254 			.est_off = EST_XGMAC_OFFSET,
255 			.fpe_reg = &dwxgmac3_fpe_reg,
256 		},
257 		.desc = &dwxgmac210_desc_ops,
258 		.dma = &dwxgmac210_dma_ops,
259 		.mac = &dwxgmac210_ops,
260 		.vlan = &dwxgmac210_vlan_ops,
261 		.hwtimestamp = &stmmac_ptp,
262 		.ptp = &stmmac_ptp_clock_ops,
263 		.mode = NULL,
264 		.tc = &dwmac510_tc_ops,
265 		.mmc = &dwxgmac_mmc_ops,
266 		.est = &dwmac510_est_ops,
267 		.setup = dwxgmac2_setup,
268 		.quirks = NULL,
269 	}, {
270 		.core_type = DWMAC_CORE_XGMAC,
271 		.min_id = DWXLGMAC_CORE_2_00,
272 		.dev_id = DWXLGMAC_ID,
273 		.regs = {
274 			.ptp_off = PTP_XGMAC_OFFSET,
275 			.mmc_off = MMC_XGMAC_OFFSET,
276 			.est_off = EST_XGMAC_OFFSET,
277 			.fpe_reg = &dwxgmac3_fpe_reg,
278 		},
279 		.desc = &dwxgmac210_desc_ops,
280 		.dma = &dwxgmac210_dma_ops,
281 		.mac = &dwxlgmac2_ops,
282 		.vlan = &dwxlgmac2_vlan_ops,
283 		.hwtimestamp = &stmmac_ptp,
284 		.ptp = &stmmac_ptp_clock_ops,
285 		.mode = NULL,
286 		.tc = &dwmac510_tc_ops,
287 		.mmc = &dwxgmac_mmc_ops,
288 		.est = &dwmac510_est_ops,
289 		.setup = dwxlgmac2_setup,
290 	},
291 };
292 
293 static const struct stmmac_hwif_entry *
stmmac_hwif_find(enum dwmac_core_type core_type,u8 snpsver,u8 dev_id)294 stmmac_hwif_find(enum dwmac_core_type core_type, u8 snpsver, u8 dev_id)
295 {
296 	const struct stmmac_hwif_entry *entry;
297 	int i;
298 
299 	for (i = ARRAY_SIZE(stmmac_hw) - 1; i >= 0; i--) {
300 		entry = &stmmac_hw[i];
301 
302 		if (core_type != entry->core_type)
303 			continue;
304 		/* Use synopsys_id var because some setups can override this */
305 		if (snpsver < entry->min_id)
306 			continue;
307 		if (core_type == DWMAC_CORE_XGMAC &&
308 		    dev_id != entry->dev_id)
309 			continue;
310 
311 		return entry;
312 	}
313 
314 	return NULL;
315 }
316 
stmmac_hwif_init(struct stmmac_priv * priv)317 int stmmac_hwif_init(struct stmmac_priv *priv)
318 {
319 	enum dwmac_core_type core_type = priv->plat->core_type;
320 	const struct stmmac_hwif_entry *entry;
321 	struct stmmac_version version;
322 	struct mac_device_info *mac;
323 	bool needs_setup = true;
324 	int ret;
325 
326 	stmmac_get_version(priv, &version);
327 
328 	/* Save ID for later use */
329 	priv->synopsys_id = version.snpsver;
330 
331 	mac = devm_kzalloc(priv->device, sizeof(*mac), GFP_KERNEL);
332 	if (!mac)
333 		return -ENOMEM;
334 
335 	/* Check for HW specific setup first */
336 	if (priv->plat->mac_setup) {
337 		ret = priv->plat->mac_setup(priv, mac);
338 		if (ret)
339 			return ret;
340 
341 		needs_setup = false;
342 	}
343 
344 	spin_lock_init(&mac->irq_ctrl_lock);
345 
346 	/* Fallback to generic HW */
347 
348 	/* Use synopsys_id var because some setups can override this */
349 	entry = stmmac_hwif_find(core_type, priv->synopsys_id, version.dev_id);
350 	if (!entry) {
351 		dev_err(priv->device,
352 			"Failed to find HW IF (id=0x%x, gmac=%d/%d)\n",
353 			version.snpsver, core_type == DWMAC_CORE_GMAC,
354 			core_type == DWMAC_CORE_GMAC4);
355 
356 		return -EINVAL;
357 	}
358 
359 	/* Only use generic HW helpers if needed */
360 	mac->desc = mac->desc ? : entry->desc;
361 	mac->dma = mac->dma ? : entry->dma;
362 	mac->mac = mac->mac ? : entry->mac;
363 	mac->ptp = mac->ptp ? : entry->hwtimestamp;
364 	mac->mode = mac->mode ? : entry->mode;
365 	mac->tc = mac->tc ? : entry->tc;
366 	mac->mmc = mac->mmc ? : entry->mmc;
367 	mac->est = mac->est ? : entry->est;
368 	mac->vlan = mac->vlan ? : entry->vlan;
369 
370 	priv->hw = mac;
371 	priv->fpe_cfg.reg = entry->regs.fpe_reg;
372 	priv->ptpaddr = priv->ioaddr + entry->regs.ptp_off;
373 	priv->mmcaddr = priv->ioaddr + entry->regs.mmc_off;
374 	memcpy(&priv->ptp_clock_ops, entry->ptp,
375 	       sizeof(struct ptp_clock_info));
376 
377 	if (entry->est)
378 		priv->estaddr = priv->ioaddr + entry->regs.est_off;
379 
380 	/* Entry found */
381 	if (needs_setup) {
382 		ret = entry->setup(priv);
383 		if (ret)
384 			return ret;
385 	}
386 
387 	/* Save quirks, if needed for posterior use */
388 	priv->hwif_quirks = entry->quirks;
389 
390 	return 0;
391 }
392