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