xref: /linux/drivers/net/ethernet/stmicro/stmmac/hwif.c (revision 44f57d78)
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 	int (*setup)(struct stmmac_priv *priv);
85 	int (*quirks)(struct stmmac_priv *priv);
86 } stmmac_hw[] = {
87 	/* NOTE: New HW versions shall go to the end of this table */
88 	{
89 		.gmac = false,
90 		.gmac4 = false,
91 		.xgmac = false,
92 		.min_id = 0,
93 		.regs = {
94 			.ptp_off = PTP_GMAC3_X_OFFSET,
95 			.mmc_off = MMC_GMAC3_X_OFFSET,
96 		},
97 		.desc = NULL,
98 		.dma = &dwmac100_dma_ops,
99 		.mac = &dwmac100_ops,
100 		.hwtimestamp = &stmmac_ptp,
101 		.mode = NULL,
102 		.tc = NULL,
103 		.setup = dwmac100_setup,
104 		.quirks = stmmac_dwmac1_quirks,
105 	}, {
106 		.gmac = true,
107 		.gmac4 = false,
108 		.xgmac = false,
109 		.min_id = 0,
110 		.regs = {
111 			.ptp_off = PTP_GMAC3_X_OFFSET,
112 			.mmc_off = MMC_GMAC3_X_OFFSET,
113 		},
114 		.desc = NULL,
115 		.dma = &dwmac1000_dma_ops,
116 		.mac = &dwmac1000_ops,
117 		.hwtimestamp = &stmmac_ptp,
118 		.mode = NULL,
119 		.tc = NULL,
120 		.setup = dwmac1000_setup,
121 		.quirks = stmmac_dwmac1_quirks,
122 	}, {
123 		.gmac = false,
124 		.gmac4 = true,
125 		.xgmac = false,
126 		.min_id = 0,
127 		.regs = {
128 			.ptp_off = PTP_GMAC4_OFFSET,
129 			.mmc_off = MMC_GMAC4_OFFSET,
130 		},
131 		.desc = &dwmac4_desc_ops,
132 		.dma = &dwmac4_dma_ops,
133 		.mac = &dwmac4_ops,
134 		.hwtimestamp = &stmmac_ptp,
135 		.mode = NULL,
136 		.tc = &dwmac510_tc_ops,
137 		.setup = dwmac4_setup,
138 		.quirks = stmmac_dwmac4_quirks,
139 	}, {
140 		.gmac = false,
141 		.gmac4 = true,
142 		.xgmac = false,
143 		.min_id = DWMAC_CORE_4_00,
144 		.regs = {
145 			.ptp_off = PTP_GMAC4_OFFSET,
146 			.mmc_off = MMC_GMAC4_OFFSET,
147 		},
148 		.desc = &dwmac4_desc_ops,
149 		.dma = &dwmac4_dma_ops,
150 		.mac = &dwmac410_ops,
151 		.hwtimestamp = &stmmac_ptp,
152 		.mode = &dwmac4_ring_mode_ops,
153 		.tc = &dwmac510_tc_ops,
154 		.setup = dwmac4_setup,
155 		.quirks = NULL,
156 	}, {
157 		.gmac = false,
158 		.gmac4 = true,
159 		.xgmac = false,
160 		.min_id = DWMAC_CORE_4_10,
161 		.regs = {
162 			.ptp_off = PTP_GMAC4_OFFSET,
163 			.mmc_off = MMC_GMAC4_OFFSET,
164 		},
165 		.desc = &dwmac4_desc_ops,
166 		.dma = &dwmac410_dma_ops,
167 		.mac = &dwmac410_ops,
168 		.hwtimestamp = &stmmac_ptp,
169 		.mode = &dwmac4_ring_mode_ops,
170 		.tc = &dwmac510_tc_ops,
171 		.setup = dwmac4_setup,
172 		.quirks = NULL,
173 	}, {
174 		.gmac = false,
175 		.gmac4 = true,
176 		.xgmac = false,
177 		.min_id = DWMAC_CORE_5_10,
178 		.regs = {
179 			.ptp_off = PTP_GMAC4_OFFSET,
180 			.mmc_off = MMC_GMAC4_OFFSET,
181 		},
182 		.desc = &dwmac4_desc_ops,
183 		.dma = &dwmac410_dma_ops,
184 		.mac = &dwmac510_ops,
185 		.hwtimestamp = &stmmac_ptp,
186 		.mode = &dwmac4_ring_mode_ops,
187 		.tc = &dwmac510_tc_ops,
188 		.setup = dwmac4_setup,
189 		.quirks = NULL,
190 	}, {
191 		.gmac = false,
192 		.gmac4 = false,
193 		.xgmac = true,
194 		.min_id = DWXGMAC_CORE_2_10,
195 		.regs = {
196 			.ptp_off = PTP_XGMAC_OFFSET,
197 			.mmc_off = 0,
198 		},
199 		.desc = &dwxgmac210_desc_ops,
200 		.dma = &dwxgmac210_dma_ops,
201 		.mac = &dwxgmac210_ops,
202 		.hwtimestamp = &stmmac_ptp,
203 		.mode = NULL,
204 		.tc = &dwmac510_tc_ops,
205 		.setup = dwxgmac2_setup,
206 		.quirks = NULL,
207 	},
208 };
209 
210 int stmmac_hwif_init(struct stmmac_priv *priv)
211 {
212 	bool needs_xgmac = priv->plat->has_xgmac;
213 	bool needs_gmac4 = priv->plat->has_gmac4;
214 	bool needs_gmac = priv->plat->has_gmac;
215 	const struct stmmac_hwif_entry *entry;
216 	struct mac_device_info *mac;
217 	bool needs_setup = true;
218 	int i, ret;
219 	u32 id;
220 
221 	if (needs_gmac) {
222 		id = stmmac_get_id(priv, GMAC_VERSION);
223 	} else if (needs_gmac4 || needs_xgmac) {
224 		id = stmmac_get_id(priv, GMAC4_VERSION);
225 	} else {
226 		id = 0;
227 	}
228 
229 	/* Save ID for later use */
230 	priv->synopsys_id = id;
231 
232 	/* Lets assume some safe values first */
233 	priv->ptpaddr = priv->ioaddr +
234 		(needs_gmac4 ? PTP_GMAC4_OFFSET : PTP_GMAC3_X_OFFSET);
235 	priv->mmcaddr = priv->ioaddr +
236 		(needs_gmac4 ? MMC_GMAC4_OFFSET : MMC_GMAC3_X_OFFSET);
237 
238 	/* Check for HW specific setup first */
239 	if (priv->plat->setup) {
240 		mac = priv->plat->setup(priv);
241 		needs_setup = false;
242 	} else {
243 		mac = devm_kzalloc(priv->device, sizeof(*mac), GFP_KERNEL);
244 	}
245 
246 	if (!mac)
247 		return -ENOMEM;
248 
249 	/* Fallback to generic HW */
250 	for (i = ARRAY_SIZE(stmmac_hw) - 1; i >= 0; i--) {
251 		entry = &stmmac_hw[i];
252 
253 		if (needs_gmac ^ entry->gmac)
254 			continue;
255 		if (needs_gmac4 ^ entry->gmac4)
256 			continue;
257 		if (needs_xgmac ^ entry->xgmac)
258 			continue;
259 		/* Use synopsys_id var because some setups can override this */
260 		if (priv->synopsys_id < entry->min_id)
261 			continue;
262 
263 		/* Only use generic HW helpers if needed */
264 		mac->desc = mac->desc ? : entry->desc;
265 		mac->dma = mac->dma ? : entry->dma;
266 		mac->mac = mac->mac ? : entry->mac;
267 		mac->ptp = mac->ptp ? : entry->hwtimestamp;
268 		mac->mode = mac->mode ? : entry->mode;
269 		mac->tc = mac->tc ? : entry->tc;
270 
271 		priv->hw = mac;
272 		priv->ptpaddr = priv->ioaddr + entry->regs.ptp_off;
273 		priv->mmcaddr = priv->ioaddr + entry->regs.mmc_off;
274 
275 		/* Entry found */
276 		if (needs_setup) {
277 			ret = entry->setup(priv);
278 			if (ret)
279 				return ret;
280 		}
281 
282 		/* Save quirks, if needed for posterior use */
283 		priv->hwif_quirks = entry->quirks;
284 		return 0;
285 	}
286 
287 	dev_err(priv->device, "Failed to find HW IF (id=0x%x, gmac=%d/%d)\n",
288 			id, needs_gmac, needs_gmac4);
289 	return -EINVAL;
290 }
291