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