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