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