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 *mode; 117 const void *tc; 118 const void *mmc; 119 const void *est; 120 int (*setup)(struct stmmac_priv *priv); 121 int (*quirks)(struct stmmac_priv *priv); 122 } stmmac_hw[] = { 123 /* NOTE: New HW versions shall go to the end of this table */ 124 { 125 .gmac = false, 126 .gmac4 = false, 127 .xgmac = false, 128 .min_id = 0, 129 .regs = { 130 .ptp_off = PTP_GMAC3_X_OFFSET, 131 .mmc_off = MMC_GMAC3_X_OFFSET, 132 }, 133 .desc = NULL, 134 .dma = &dwmac100_dma_ops, 135 .mac = &dwmac100_ops, 136 .hwtimestamp = &stmmac_ptp, 137 .mode = NULL, 138 .tc = NULL, 139 .mmc = &dwmac_mmc_ops, 140 .setup = dwmac100_setup, 141 .quirks = stmmac_dwmac1_quirks, 142 }, { 143 .gmac = true, 144 .gmac4 = false, 145 .xgmac = false, 146 .min_id = 0, 147 .regs = { 148 .ptp_off = PTP_GMAC3_X_OFFSET, 149 .mmc_off = MMC_GMAC3_X_OFFSET, 150 }, 151 .desc = NULL, 152 .dma = &dwmac1000_dma_ops, 153 .mac = &dwmac1000_ops, 154 .hwtimestamp = &stmmac_ptp, 155 .mode = NULL, 156 .tc = NULL, 157 .mmc = &dwmac_mmc_ops, 158 .setup = dwmac1000_setup, 159 .quirks = stmmac_dwmac1_quirks, 160 }, { 161 .gmac = false, 162 .gmac4 = true, 163 .xgmac = false, 164 .min_id = 0, 165 .regs = { 166 .ptp_off = PTP_GMAC4_OFFSET, 167 .mmc_off = MMC_GMAC4_OFFSET, 168 .est_off = EST_GMAC4_OFFSET, 169 }, 170 .desc = &dwmac4_desc_ops, 171 .dma = &dwmac4_dma_ops, 172 .mac = &dwmac4_ops, 173 .hwtimestamp = &stmmac_ptp, 174 .mode = NULL, 175 .tc = &dwmac4_tc_ops, 176 .mmc = &dwmac_mmc_ops, 177 .est = &dwmac510_est_ops, 178 .setup = dwmac4_setup, 179 .quirks = stmmac_dwmac4_quirks, 180 }, { 181 .gmac = false, 182 .gmac4 = true, 183 .xgmac = false, 184 .min_id = DWMAC_CORE_4_00, 185 .regs = { 186 .ptp_off = PTP_GMAC4_OFFSET, 187 .mmc_off = MMC_GMAC4_OFFSET, 188 .est_off = EST_GMAC4_OFFSET, 189 .fpe_reg = &dwmac5_fpe_reg, 190 }, 191 .desc = &dwmac4_desc_ops, 192 .dma = &dwmac4_dma_ops, 193 .mac = &dwmac410_ops, 194 .hwtimestamp = &stmmac_ptp, 195 .mode = &dwmac4_ring_mode_ops, 196 .tc = &dwmac510_tc_ops, 197 .mmc = &dwmac_mmc_ops, 198 .est = &dwmac510_est_ops, 199 .setup = dwmac4_setup, 200 .quirks = NULL, 201 }, { 202 .gmac = false, 203 .gmac4 = true, 204 .xgmac = false, 205 .min_id = DWMAC_CORE_4_10, 206 .regs = { 207 .ptp_off = PTP_GMAC4_OFFSET, 208 .mmc_off = MMC_GMAC4_OFFSET, 209 .est_off = EST_GMAC4_OFFSET, 210 .fpe_reg = &dwmac5_fpe_reg, 211 }, 212 .desc = &dwmac4_desc_ops, 213 .dma = &dwmac410_dma_ops, 214 .mac = &dwmac410_ops, 215 .hwtimestamp = &stmmac_ptp, 216 .mode = &dwmac4_ring_mode_ops, 217 .tc = &dwmac510_tc_ops, 218 .mmc = &dwmac_mmc_ops, 219 .est = &dwmac510_est_ops, 220 .setup = dwmac4_setup, 221 .quirks = NULL, 222 }, { 223 .gmac = false, 224 .gmac4 = true, 225 .xgmac = false, 226 .min_id = DWMAC_CORE_5_10, 227 .regs = { 228 .ptp_off = PTP_GMAC4_OFFSET, 229 .mmc_off = MMC_GMAC4_OFFSET, 230 .est_off = EST_GMAC4_OFFSET, 231 .fpe_reg = &dwmac5_fpe_reg, 232 }, 233 .desc = &dwmac4_desc_ops, 234 .dma = &dwmac410_dma_ops, 235 .mac = &dwmac510_ops, 236 .hwtimestamp = &stmmac_ptp, 237 .mode = &dwmac4_ring_mode_ops, 238 .tc = &dwmac510_tc_ops, 239 .mmc = &dwmac_mmc_ops, 240 .est = &dwmac510_est_ops, 241 .setup = dwmac4_setup, 242 .quirks = NULL, 243 }, { 244 .gmac = false, 245 .gmac4 = false, 246 .xgmac = true, 247 .min_id = DWXGMAC_CORE_2_10, 248 .dev_id = DWXGMAC_ID, 249 .regs = { 250 .ptp_off = PTP_XGMAC_OFFSET, 251 .mmc_off = MMC_XGMAC_OFFSET, 252 .est_off = EST_XGMAC_OFFSET, 253 .fpe_reg = &dwxgmac3_fpe_reg, 254 }, 255 .desc = &dwxgmac210_desc_ops, 256 .dma = &dwxgmac210_dma_ops, 257 .mac = &dwxgmac210_ops, 258 .hwtimestamp = &stmmac_ptp, 259 .mode = NULL, 260 .tc = &dwxgmac_tc_ops, 261 .mmc = &dwxgmac_mmc_ops, 262 .est = &dwmac510_est_ops, 263 .setup = dwxgmac2_setup, 264 .quirks = NULL, 265 }, { 266 .gmac = false, 267 .gmac4 = false, 268 .xgmac = true, 269 .min_id = DWXLGMAC_CORE_2_00, 270 .dev_id = DWXLGMAC_ID, 271 .regs = { 272 .ptp_off = PTP_XGMAC_OFFSET, 273 .mmc_off = MMC_XGMAC_OFFSET, 274 .est_off = EST_XGMAC_OFFSET, 275 .fpe_reg = &dwxgmac3_fpe_reg, 276 }, 277 .desc = &dwxgmac210_desc_ops, 278 .dma = &dwxgmac210_dma_ops, 279 .mac = &dwxlgmac2_ops, 280 .hwtimestamp = &stmmac_ptp, 281 .mode = NULL, 282 .tc = &dwxgmac_tc_ops, 283 .mmc = &dwxgmac_mmc_ops, 284 .est = &dwmac510_est_ops, 285 .setup = dwxlgmac2_setup, 286 .quirks = stmmac_dwxlgmac_quirks, 287 }, 288 }; 289 290 int stmmac_hwif_init(struct stmmac_priv *priv) 291 { 292 bool needs_xgmac = priv->plat->has_xgmac; 293 bool needs_gmac4 = priv->plat->has_gmac4; 294 bool needs_gmac = priv->plat->has_gmac; 295 const struct stmmac_hwif_entry *entry; 296 struct mac_device_info *mac; 297 bool needs_setup = true; 298 u32 id, dev_id = 0; 299 int i, ret; 300 301 if (needs_gmac) { 302 id = stmmac_get_id(priv, GMAC_VERSION); 303 } else if (needs_gmac4 || needs_xgmac) { 304 id = stmmac_get_id(priv, GMAC4_VERSION); 305 if (needs_xgmac) 306 dev_id = stmmac_get_dev_id(priv, GMAC4_VERSION); 307 } else { 308 id = 0; 309 } 310 311 /* Save ID for later use */ 312 priv->synopsys_id = id; 313 314 /* Lets assume some safe values first */ 315 priv->ptpaddr = priv->ioaddr + 316 (needs_gmac4 ? PTP_GMAC4_OFFSET : PTP_GMAC3_X_OFFSET); 317 priv->mmcaddr = priv->ioaddr + 318 (needs_gmac4 ? MMC_GMAC4_OFFSET : MMC_GMAC3_X_OFFSET); 319 if (needs_gmac4) 320 priv->estaddr = priv->ioaddr + EST_GMAC4_OFFSET; 321 else if (needs_xgmac) 322 priv->estaddr = priv->ioaddr + EST_XGMAC_OFFSET; 323 324 /* Check for HW specific setup first */ 325 if (priv->plat->setup) { 326 mac = priv->plat->setup(priv); 327 needs_setup = false; 328 } else { 329 mac = devm_kzalloc(priv->device, sizeof(*mac), GFP_KERNEL); 330 } 331 332 if (!mac) 333 return -ENOMEM; 334 335 /* Fallback to generic HW */ 336 for (i = ARRAY_SIZE(stmmac_hw) - 1; i >= 0; i--) { 337 entry = &stmmac_hw[i]; 338 339 if (needs_gmac ^ entry->gmac) 340 continue; 341 if (needs_gmac4 ^ entry->gmac4) 342 continue; 343 if (needs_xgmac ^ entry->xgmac) 344 continue; 345 /* Use synopsys_id var because some setups can override this */ 346 if (priv->synopsys_id < entry->min_id) 347 continue; 348 if (needs_xgmac && (dev_id ^ entry->dev_id)) 349 continue; 350 351 /* Only use generic HW helpers if needed */ 352 mac->desc = mac->desc ? : entry->desc; 353 mac->dma = mac->dma ? : entry->dma; 354 mac->mac = mac->mac ? : entry->mac; 355 mac->ptp = mac->ptp ? : entry->hwtimestamp; 356 mac->mode = mac->mode ? : entry->mode; 357 mac->tc = mac->tc ? : entry->tc; 358 mac->mmc = mac->mmc ? : entry->mmc; 359 mac->est = mac->est ? : entry->est; 360 361 priv->hw = mac; 362 priv->fpe_cfg.reg = entry->regs.fpe_reg; 363 priv->ptpaddr = priv->ioaddr + entry->regs.ptp_off; 364 priv->mmcaddr = priv->ioaddr + entry->regs.mmc_off; 365 if (entry->est) 366 priv->estaddr = priv->ioaddr + entry->regs.est_off; 367 368 /* Entry found */ 369 if (needs_setup) { 370 ret = entry->setup(priv); 371 if (ret) 372 return ret; 373 } 374 375 /* Save quirks, if needed for posterior use */ 376 priv->hwif_quirks = entry->quirks; 377 return 0; 378 } 379 380 dev_err(priv->device, "Failed to find HW IF (id=0x%x, gmac=%d/%d)\n", 381 id, needs_gmac, needs_gmac4); 382 return -EINVAL; 383 } 384