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 10 static u32 stmmac_get_id(struct stmmac_priv *priv, u32 id_reg) 11 { 12 u32 reg = readl(priv->ioaddr + id_reg); 13 14 if (!reg) { 15 dev_info(priv->device, "Version ID not available\n"); 16 return 0x0; 17 } 18 19 dev_info(priv->device, "User ID: 0x%x, Synopsys ID: 0x%x\n", 20 (unsigned int)(reg & GENMASK(15, 8)) >> 8, 21 (unsigned int)(reg & GENMASK(7, 0))); 22 return reg & GENMASK(7, 0); 23 } 24 25 static void stmmac_dwmac_mode_quirk(struct stmmac_priv *priv) 26 { 27 struct mac_device_info *mac = priv->hw; 28 29 if (priv->chain_mode) { 30 dev_info(priv->device, "Chain mode enabled\n"); 31 priv->mode = STMMAC_CHAIN_MODE; 32 mac->mode = &chain_mode_ops; 33 } else { 34 dev_info(priv->device, "Ring mode enabled\n"); 35 priv->mode = STMMAC_RING_MODE; 36 mac->mode = &ring_mode_ops; 37 } 38 } 39 40 static int stmmac_dwmac1_quirks(struct stmmac_priv *priv) 41 { 42 struct mac_device_info *mac = priv->hw; 43 44 if (priv->plat->enh_desc) { 45 dev_info(priv->device, "Enhanced/Alternate descriptors\n"); 46 47 /* GMAC older than 3.50 has no extended descriptors */ 48 if (priv->synopsys_id >= DWMAC_CORE_3_50) { 49 dev_info(priv->device, "Enabled extended descriptors\n"); 50 priv->extend_desc = 1; 51 } else { 52 dev_warn(priv->device, "Extended descriptors not supported\n"); 53 } 54 55 mac->desc = &enh_desc_ops; 56 } else { 57 dev_info(priv->device, "Normal descriptors\n"); 58 mac->desc = &ndesc_ops; 59 } 60 61 stmmac_dwmac_mode_quirk(priv); 62 return 0; 63 } 64 65 static int stmmac_dwmac4_quirks(struct stmmac_priv *priv) 66 { 67 stmmac_dwmac_mode_quirk(priv); 68 return 0; 69 } 70 71 static const struct stmmac_hwif_entry { 72 bool gmac; 73 bool gmac4; 74 u32 min_id; 75 const void *desc; 76 const void *dma; 77 const void *mac; 78 const void *hwtimestamp; 79 const void *mode; 80 int (*setup)(struct stmmac_priv *priv); 81 int (*quirks)(struct stmmac_priv *priv); 82 } stmmac_hw[] = { 83 /* NOTE: New HW versions shall go to the end of this table */ 84 { 85 .gmac = false, 86 .gmac4 = false, 87 .min_id = 0, 88 .desc = NULL, 89 .dma = &dwmac100_dma_ops, 90 .mac = &dwmac100_ops, 91 .hwtimestamp = &stmmac_ptp, 92 .mode = NULL, 93 .setup = dwmac100_setup, 94 .quirks = stmmac_dwmac1_quirks, 95 }, { 96 .gmac = true, 97 .gmac4 = false, 98 .min_id = 0, 99 .desc = NULL, 100 .dma = &dwmac1000_dma_ops, 101 .mac = &dwmac1000_ops, 102 .hwtimestamp = &stmmac_ptp, 103 .mode = NULL, 104 .setup = dwmac1000_setup, 105 .quirks = stmmac_dwmac1_quirks, 106 }, { 107 .gmac = false, 108 .gmac4 = true, 109 .min_id = 0, 110 .desc = &dwmac4_desc_ops, 111 .dma = &dwmac4_dma_ops, 112 .mac = &dwmac4_ops, 113 .hwtimestamp = &stmmac_ptp, 114 .mode = NULL, 115 .setup = dwmac4_setup, 116 .quirks = stmmac_dwmac4_quirks, 117 }, { 118 .gmac = false, 119 .gmac4 = true, 120 .min_id = DWMAC_CORE_4_00, 121 .desc = &dwmac4_desc_ops, 122 .dma = &dwmac4_dma_ops, 123 .mac = &dwmac410_ops, 124 .hwtimestamp = &stmmac_ptp, 125 .mode = &dwmac4_ring_mode_ops, 126 .setup = dwmac4_setup, 127 .quirks = NULL, 128 }, { 129 .gmac = false, 130 .gmac4 = true, 131 .min_id = DWMAC_CORE_4_10, 132 .desc = &dwmac4_desc_ops, 133 .dma = &dwmac410_dma_ops, 134 .mac = &dwmac410_ops, 135 .hwtimestamp = &stmmac_ptp, 136 .mode = &dwmac4_ring_mode_ops, 137 .setup = dwmac4_setup, 138 .quirks = NULL, 139 }, { 140 .gmac = false, 141 .gmac4 = true, 142 .min_id = DWMAC_CORE_5_10, 143 .desc = &dwmac4_desc_ops, 144 .dma = &dwmac410_dma_ops, 145 .mac = &dwmac510_ops, 146 .hwtimestamp = &stmmac_ptp, 147 .mode = &dwmac4_ring_mode_ops, 148 .setup = dwmac4_setup, 149 .quirks = NULL, 150 } 151 }; 152 153 int stmmac_hwif_init(struct stmmac_priv *priv) 154 { 155 bool needs_gmac4 = priv->plat->has_gmac4; 156 bool needs_gmac = priv->plat->has_gmac; 157 const struct stmmac_hwif_entry *entry; 158 struct mac_device_info *mac; 159 int i, ret; 160 u32 id; 161 162 if (needs_gmac) { 163 id = stmmac_get_id(priv, GMAC_VERSION); 164 } else { 165 id = stmmac_get_id(priv, GMAC4_VERSION); 166 } 167 168 /* Save ID for later use */ 169 priv->synopsys_id = id; 170 171 /* Check for HW specific setup first */ 172 if (priv->plat->setup) { 173 priv->hw = priv->plat->setup(priv); 174 if (!priv->hw) 175 return -ENOMEM; 176 return 0; 177 } 178 179 mac = devm_kzalloc(priv->device, sizeof(*mac), GFP_KERNEL); 180 if (!mac) 181 return -ENOMEM; 182 183 /* Fallback to generic HW */ 184 for (i = ARRAY_SIZE(stmmac_hw) - 1; i >= 0; i--) { 185 entry = &stmmac_hw[i]; 186 187 if (needs_gmac ^ entry->gmac) 188 continue; 189 if (needs_gmac4 ^ entry->gmac4) 190 continue; 191 if (id < entry->min_id) 192 continue; 193 194 mac->desc = entry->desc; 195 mac->dma = entry->dma; 196 mac->mac = entry->mac; 197 mac->ptp = entry->hwtimestamp; 198 mac->mode = entry->mode; 199 200 priv->hw = mac; 201 202 /* Entry found */ 203 ret = entry->setup(priv); 204 if (ret) 205 return ret; 206 207 /* Run quirks, if needed */ 208 if (entry->quirks) { 209 ret = entry->quirks(priv); 210 if (ret) 211 return ret; 212 } 213 214 return 0; 215 } 216 217 dev_err(priv->device, "Failed to find HW IF (id=0x%x, gmac=%d/%d)\n", 218 id, needs_gmac, needs_gmac4); 219 return -EINVAL; 220 } 221