1 // SPDX-License-Identifier: (GPL-2.0 OR MIT)
3 * Copyright (c) 2018 Synopsys, Inc. and/or its affiliates.
4 * stmmac HW Interface Handling
9 #include "stmmac_ptp.h"
11 static u32
stmmac_get_id(struct stmmac_priv
*priv
, u32 id_reg
)
13 u32 reg
= readl(priv
->ioaddr
+ id_reg
);
16 dev_info(priv
->device
, "Version ID not available\n");
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);
26 static void stmmac_dwmac_mode_quirk(struct stmmac_priv
*priv
)
28 struct mac_device_info
*mac
= priv
->hw
;
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
;
35 dev_info(priv
->device
, "Ring mode enabled\n");
36 priv
->mode
= STMMAC_RING_MODE
;
37 mac
->mode
= &ring_mode_ops
;
41 static int stmmac_dwmac1_quirks(struct stmmac_priv
*priv
)
43 struct mac_device_info
*mac
= priv
->hw
;
45 if (priv
->plat
->enh_desc
) {
46 dev_info(priv
->device
, "Enhanced/Alternate descriptors\n");
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;
53 dev_warn(priv
->device
, "Extended descriptors not supported\n");
56 mac
->desc
= &enh_desc_ops
;
58 dev_info(priv
->device
, "Normal descriptors\n");
59 mac
->desc
= &ndesc_ops
;
62 stmmac_dwmac_mode_quirk(priv
);
66 static int stmmac_dwmac4_quirks(struct stmmac_priv
*priv
)
68 stmmac_dwmac_mode_quirk(priv
);
72 static const struct stmmac_hwif_entry
{
77 const struct stmmac_regs_off regs
;
81 const void *hwtimestamp
;
84 int (*setup
)(struct stmmac_priv
*priv
);
85 int (*quirks
)(struct stmmac_priv
*priv
);
87 /* NOTE: New HW versions shall go to the end of this table */
94 .ptp_off
= PTP_GMAC3_X_OFFSET
,
95 .mmc_off
= MMC_GMAC3_X_OFFSET
,
98 .dma
= &dwmac100_dma_ops
,
100 .hwtimestamp
= &stmmac_ptp
,
103 .setup
= dwmac100_setup
,
104 .quirks
= stmmac_dwmac1_quirks
,
111 .ptp_off
= PTP_GMAC3_X_OFFSET
,
112 .mmc_off
= MMC_GMAC3_X_OFFSET
,
115 .dma
= &dwmac1000_dma_ops
,
116 .mac
= &dwmac1000_ops
,
117 .hwtimestamp
= &stmmac_ptp
,
120 .setup
= dwmac1000_setup
,
121 .quirks
= stmmac_dwmac1_quirks
,
128 .ptp_off
= PTP_GMAC4_OFFSET
,
129 .mmc_off
= MMC_GMAC4_OFFSET
,
131 .desc
= &dwmac4_desc_ops
,
132 .dma
= &dwmac4_dma_ops
,
134 .hwtimestamp
= &stmmac_ptp
,
136 .tc
= &dwmac510_tc_ops
,
137 .setup
= dwmac4_setup
,
138 .quirks
= stmmac_dwmac4_quirks
,
143 .min_id
= DWMAC_CORE_4_00
,
145 .ptp_off
= PTP_GMAC4_OFFSET
,
146 .mmc_off
= MMC_GMAC4_OFFSET
,
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
,
160 .min_id
= DWMAC_CORE_4_10
,
162 .ptp_off
= PTP_GMAC4_OFFSET
,
163 .mmc_off
= MMC_GMAC4_OFFSET
,
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
,
177 .min_id
= DWMAC_CORE_5_10
,
179 .ptp_off
= PTP_GMAC4_OFFSET
,
180 .mmc_off
= MMC_GMAC4_OFFSET
,
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
,
194 .min_id
= DWXGMAC_CORE_2_10
,
196 .ptp_off
= PTP_XGMAC_OFFSET
,
199 .desc
= &dwxgmac210_desc_ops
,
200 .dma
= &dwxgmac210_dma_ops
,
201 .mac
= &dwxgmac210_ops
,
202 .hwtimestamp
= &stmmac_ptp
,
204 .tc
= &dwmac510_tc_ops
,
205 .setup
= dwxgmac2_setup
,
210 int stmmac_hwif_init(struct stmmac_priv
*priv
)
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;
222 id
= stmmac_get_id(priv
, GMAC_VERSION
);
223 } else if (needs_gmac4
|| needs_xgmac
) {
224 id
= stmmac_get_id(priv
, GMAC4_VERSION
);
229 /* Save ID for later use */
230 priv
->synopsys_id
= id
;
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
);
238 /* Check for HW specific setup first */
239 if (priv
->plat
->setup
) {
240 mac
= priv
->plat
->setup(priv
);
243 mac
= devm_kzalloc(priv
->device
, sizeof(*mac
), GFP_KERNEL
);
249 /* Fallback to generic HW */
250 for (i
= ARRAY_SIZE(stmmac_hw
) - 1; i
>= 0; i
--) {
251 entry
= &stmmac_hw
[i
];
253 if (needs_gmac
^ entry
->gmac
)
255 if (needs_gmac4
^ entry
->gmac4
)
257 if (needs_xgmac
^ entry
->xgmac
)
259 /* Use synopsys_id var because some setups can override this */
260 if (priv
->synopsys_id
< entry
->min_id
)
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
;
272 priv
->ptpaddr
= priv
->ioaddr
+ entry
->regs
.ptp_off
;
273 priv
->mmcaddr
= priv
->ioaddr
+ entry
->regs
.mmc_off
;
277 ret
= entry
->setup(priv
);
282 /* Save quirks, if needed for posterior use */
283 priv
->hwif_quirks
= entry
->quirks
;
287 dev_err(priv
->device
, "Failed to find HW IF (id=0x%x, gmac=%d/%d)\n",
288 id
, needs_gmac
, needs_gmac4
);