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