Linux-libre 5.4.49-gnu
[librecmc/linux-libre.git] / drivers / net / ethernet / stmicro / stmmac / hwif.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_ptp.h"
10
11 static u32 stmmac_get_id(struct stmmac_priv *priv, u32 id_reg)
12 {
13         u32 reg = readl(priv->ioaddr + id_reg);
14
15         if (!reg) {
16                 dev_info(priv->device, "Version ID not available\n");
17                 return 0x0;
18         }
19
20         dev_info(priv->device, "User ID: 0x%x, Synopsys ID: 0x%x\n",
21                         (unsigned int)(reg & GENMASK(15, 8)) >> 8,
22                         (unsigned int)(reg & GENMASK(7, 0)));
23         return reg & GENMASK(7, 0);
24 }
25
26 static void stmmac_dwmac_mode_quirk(struct stmmac_priv *priv)
27 {
28         struct mac_device_info *mac = priv->hw;
29
30         if (priv->chain_mode) {
31                 dev_info(priv->device, "Chain mode enabled\n");
32                 priv->mode = STMMAC_CHAIN_MODE;
33                 mac->mode = &chain_mode_ops;
34         } else {
35                 dev_info(priv->device, "Ring mode enabled\n");
36                 priv->mode = STMMAC_RING_MODE;
37                 mac->mode = &ring_mode_ops;
38         }
39 }
40
41 static int stmmac_dwmac1_quirks(struct stmmac_priv *priv)
42 {
43         struct mac_device_info *mac = priv->hw;
44
45         if (priv->plat->enh_desc) {
46                 dev_info(priv->device, "Enhanced/Alternate descriptors\n");
47
48                 /* GMAC older than 3.50 has no extended descriptors */
49                 if (priv->synopsys_id >= DWMAC_CORE_3_50) {
50                         dev_info(priv->device, "Enabled extended descriptors\n");
51                         priv->extend_desc = 1;
52                 } else {
53                         dev_warn(priv->device, "Extended descriptors not supported\n");
54                 }
55
56                 mac->desc = &enh_desc_ops;
57         } else {
58                 dev_info(priv->device, "Normal descriptors\n");
59                 mac->desc = &ndesc_ops;
60         }
61
62         stmmac_dwmac_mode_quirk(priv);
63         return 0;
64 }
65
66 static int stmmac_dwmac4_quirks(struct stmmac_priv *priv)
67 {
68         stmmac_dwmac_mode_quirk(priv);
69         return 0;
70 }
71
72 static const struct stmmac_hwif_entry {
73         bool gmac;
74         bool gmac4;
75         bool xgmac;
76         u32 min_id;
77         const struct stmmac_regs_off regs;
78         const void *desc;
79         const void *dma;
80         const void *mac;
81         const void *hwtimestamp;
82         const void *mode;
83         const void *tc;
84         const void *mmc;
85         int (*setup)(struct stmmac_priv *priv);
86         int (*quirks)(struct stmmac_priv *priv);
87 } stmmac_hw[] = {
88         /* NOTE: New HW versions shall go to the end of this table */
89         {
90                 .gmac = false,
91                 .gmac4 = false,
92                 .xgmac = false,
93                 .min_id = 0,
94                 .regs = {
95                         .ptp_off = PTP_GMAC3_X_OFFSET,
96                         .mmc_off = MMC_GMAC3_X_OFFSET,
97                 },
98                 .desc = NULL,
99                 .dma = &dwmac100_dma_ops,
100                 .mac = &dwmac100_ops,
101                 .hwtimestamp = &stmmac_ptp,
102                 .mode = NULL,
103                 .tc = NULL,
104                 .mmc = &dwmac_mmc_ops,
105                 .setup = dwmac100_setup,
106                 .quirks = stmmac_dwmac1_quirks,
107         }, {
108                 .gmac = true,
109                 .gmac4 = false,
110                 .xgmac = false,
111                 .min_id = 0,
112                 .regs = {
113                         .ptp_off = PTP_GMAC3_X_OFFSET,
114                         .mmc_off = MMC_GMAC3_X_OFFSET,
115                 },
116                 .desc = NULL,
117                 .dma = &dwmac1000_dma_ops,
118                 .mac = &dwmac1000_ops,
119                 .hwtimestamp = &stmmac_ptp,
120                 .mode = NULL,
121                 .tc = NULL,
122                 .mmc = &dwmac_mmc_ops,
123                 .setup = dwmac1000_setup,
124                 .quirks = stmmac_dwmac1_quirks,
125         }, {
126                 .gmac = false,
127                 .gmac4 = true,
128                 .xgmac = false,
129                 .min_id = 0,
130                 .regs = {
131                         .ptp_off = PTP_GMAC4_OFFSET,
132                         .mmc_off = MMC_GMAC4_OFFSET,
133                 },
134                 .desc = &dwmac4_desc_ops,
135                 .dma = &dwmac4_dma_ops,
136                 .mac = &dwmac4_ops,
137                 .hwtimestamp = &stmmac_ptp,
138                 .mode = NULL,
139                 .tc = &dwmac510_tc_ops,
140                 .mmc = &dwmac_mmc_ops,
141                 .setup = dwmac4_setup,
142                 .quirks = stmmac_dwmac4_quirks,
143         }, {
144                 .gmac = false,
145                 .gmac4 = true,
146                 .xgmac = false,
147                 .min_id = DWMAC_CORE_4_00,
148                 .regs = {
149                         .ptp_off = PTP_GMAC4_OFFSET,
150                         .mmc_off = MMC_GMAC4_OFFSET,
151                 },
152                 .desc = &dwmac4_desc_ops,
153                 .dma = &dwmac4_dma_ops,
154                 .mac = &dwmac410_ops,
155                 .hwtimestamp = &stmmac_ptp,
156                 .mode = &dwmac4_ring_mode_ops,
157                 .tc = &dwmac510_tc_ops,
158                 .mmc = &dwmac_mmc_ops,
159                 .setup = dwmac4_setup,
160                 .quirks = NULL,
161         }, {
162                 .gmac = false,
163                 .gmac4 = true,
164                 .xgmac = false,
165                 .min_id = DWMAC_CORE_4_10,
166                 .regs = {
167                         .ptp_off = PTP_GMAC4_OFFSET,
168                         .mmc_off = MMC_GMAC4_OFFSET,
169                 },
170                 .desc = &dwmac4_desc_ops,
171                 .dma = &dwmac410_dma_ops,
172                 .mac = &dwmac410_ops,
173                 .hwtimestamp = &stmmac_ptp,
174                 .mode = &dwmac4_ring_mode_ops,
175                 .tc = &dwmac510_tc_ops,
176                 .mmc = &dwmac_mmc_ops,
177                 .setup = dwmac4_setup,
178                 .quirks = NULL,
179         }, {
180                 .gmac = false,
181                 .gmac4 = true,
182                 .xgmac = false,
183                 .min_id = DWMAC_CORE_5_10,
184                 .regs = {
185                         .ptp_off = PTP_GMAC4_OFFSET,
186                         .mmc_off = MMC_GMAC4_OFFSET,
187                 },
188                 .desc = &dwmac4_desc_ops,
189                 .dma = &dwmac410_dma_ops,
190                 .mac = &dwmac510_ops,
191                 .hwtimestamp = &stmmac_ptp,
192                 .mode = &dwmac4_ring_mode_ops,
193                 .tc = &dwmac510_tc_ops,
194                 .mmc = &dwmac_mmc_ops,
195                 .setup = dwmac4_setup,
196                 .quirks = NULL,
197         }, {
198                 .gmac = false,
199                 .gmac4 = false,
200                 .xgmac = true,
201                 .min_id = DWXGMAC_CORE_2_10,
202                 .regs = {
203                         .ptp_off = PTP_XGMAC_OFFSET,
204                         .mmc_off = MMC_XGMAC_OFFSET,
205                 },
206                 .desc = &dwxgmac210_desc_ops,
207                 .dma = &dwxgmac210_dma_ops,
208                 .mac = &dwxgmac210_ops,
209                 .hwtimestamp = &stmmac_ptp,
210                 .mode = NULL,
211                 .tc = &dwmac510_tc_ops,
212                 .mmc = &dwxgmac_mmc_ops,
213                 .setup = dwxgmac2_setup,
214                 .quirks = NULL,
215         },
216 };
217
218 int stmmac_hwif_init(struct stmmac_priv *priv)
219 {
220         bool needs_xgmac = priv->plat->has_xgmac;
221         bool needs_gmac4 = priv->plat->has_gmac4;
222         bool needs_gmac = priv->plat->has_gmac;
223         const struct stmmac_hwif_entry *entry;
224         struct mac_device_info *mac;
225         bool needs_setup = true;
226         int i, ret;
227         u32 id;
228
229         if (needs_gmac) {
230                 id = stmmac_get_id(priv, GMAC_VERSION);
231         } else if (needs_gmac4 || needs_xgmac) {
232                 id = stmmac_get_id(priv, GMAC4_VERSION);
233         } else {
234                 id = 0;
235         }
236
237         /* Save ID for later use */
238         priv->synopsys_id = id;
239
240         /* Lets assume some safe values first */
241         priv->ptpaddr = priv->ioaddr +
242                 (needs_gmac4 ? PTP_GMAC4_OFFSET : PTP_GMAC3_X_OFFSET);
243         priv->mmcaddr = priv->ioaddr +
244                 (needs_gmac4 ? MMC_GMAC4_OFFSET : MMC_GMAC3_X_OFFSET);
245
246         /* Check for HW specific setup first */
247         if (priv->plat->setup) {
248                 mac = priv->plat->setup(priv);
249                 needs_setup = false;
250         } else {
251                 mac = devm_kzalloc(priv->device, sizeof(*mac), GFP_KERNEL);
252         }
253
254         if (!mac)
255                 return -ENOMEM;
256
257         /* Fallback to generic HW */
258         for (i = ARRAY_SIZE(stmmac_hw) - 1; i >= 0; i--) {
259                 entry = &stmmac_hw[i];
260
261                 if (needs_gmac ^ entry->gmac)
262                         continue;
263                 if (needs_gmac4 ^ entry->gmac4)
264                         continue;
265                 if (needs_xgmac ^ entry->xgmac)
266                         continue;
267                 /* Use synopsys_id var because some setups can override this */
268                 if (priv->synopsys_id < entry->min_id)
269                         continue;
270
271                 /* Only use generic HW helpers if needed */
272                 mac->desc = mac->desc ? : entry->desc;
273                 mac->dma = mac->dma ? : entry->dma;
274                 mac->mac = mac->mac ? : entry->mac;
275                 mac->ptp = mac->ptp ? : entry->hwtimestamp;
276                 mac->mode = mac->mode ? : entry->mode;
277                 mac->tc = mac->tc ? : entry->tc;
278                 mac->mmc = mac->mmc ? : entry->mmc;
279
280                 priv->hw = mac;
281                 priv->ptpaddr = priv->ioaddr + entry->regs.ptp_off;
282                 priv->mmcaddr = priv->ioaddr + entry->regs.mmc_off;
283
284                 /* Entry found */
285                 if (needs_setup) {
286                         ret = entry->setup(priv);
287                         if (ret)
288                                 return ret;
289                 }
290
291                 /* Save quirks, if needed for posterior use */
292                 priv->hwif_quirks = entry->quirks;
293                 return 0;
294         }
295
296         dev_err(priv->device, "Failed to find HW IF (id=0x%x, gmac=%d/%d)\n",
297                         id, needs_gmac, needs_gmac4);
298         return -EINVAL;
299 }