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