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