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