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