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 const void *tc; 81 int (*setup)(struct stmmac_priv *priv); 82 int (*quirks)(struct stmmac_priv *priv); 83 } stmmac_hw[] = { 84 /* NOTE: New HW versions shall go to the end of this table */ 85 { 86 .gmac = false, 87 .gmac4 = false, 88 .min_id = 0, 89 .desc = NULL, 90 .dma = &dwmac100_dma_ops, 91 .mac = &dwmac100_ops, 92 .hwtimestamp = &stmmac_ptp, 93 .mode = NULL, 94 .tc = NULL, 95 .setup = dwmac100_setup, 96 .quirks = stmmac_dwmac1_quirks, 97 }, { 98 .gmac = true, 99 .gmac4 = false, 100 .min_id = 0, 101 .desc = NULL, 102 .dma = &dwmac1000_dma_ops, 103 .mac = &dwmac1000_ops, 104 .hwtimestamp = &stmmac_ptp, 105 .mode = NULL, 106 .tc = NULL, 107 .setup = dwmac1000_setup, 108 .quirks = stmmac_dwmac1_quirks, 109 }, { 110 .gmac = false, 111 .gmac4 = true, 112 .min_id = 0, 113 .desc = &dwmac4_desc_ops, 114 .dma = &dwmac4_dma_ops, 115 .mac = &dwmac4_ops, 116 .hwtimestamp = &stmmac_ptp, 117 .mode = NULL, 118 .tc = NULL, 119 .setup = dwmac4_setup, 120 .quirks = stmmac_dwmac4_quirks, 121 }, { 122 .gmac = false, 123 .gmac4 = true, 124 .min_id = DWMAC_CORE_4_00, 125 .desc = &dwmac4_desc_ops, 126 .dma = &dwmac4_dma_ops, 127 .mac = &dwmac410_ops, 128 .hwtimestamp = &stmmac_ptp, 129 .mode = &dwmac4_ring_mode_ops, 130 .tc = NULL, 131 .setup = dwmac4_setup, 132 .quirks = NULL, 133 }, { 134 .gmac = false, 135 .gmac4 = true, 136 .min_id = DWMAC_CORE_4_10, 137 .desc = &dwmac4_desc_ops, 138 .dma = &dwmac410_dma_ops, 139 .mac = &dwmac410_ops, 140 .hwtimestamp = &stmmac_ptp, 141 .mode = &dwmac4_ring_mode_ops, 142 .tc = NULL, 143 .setup = dwmac4_setup, 144 .quirks = NULL, 145 }, { 146 .gmac = false, 147 .gmac4 = true, 148 .min_id = DWMAC_CORE_5_10, 149 .desc = &dwmac4_desc_ops, 150 .dma = &dwmac410_dma_ops, 151 .mac = &dwmac510_ops, 152 .hwtimestamp = &stmmac_ptp, 153 .mode = &dwmac4_ring_mode_ops, 154 .tc = &dwmac510_tc_ops, 155 .setup = dwmac4_setup, 156 .quirks = NULL, 157 } 158 }; 159 160 int stmmac_hwif_init(struct stmmac_priv *priv) 161 { 162 bool needs_gmac4 = priv->plat->has_gmac4; 163 bool needs_gmac = priv->plat->has_gmac; 164 const struct stmmac_hwif_entry *entry; 165 struct mac_device_info *mac; 166 int i, ret; 167 u32 id; 168 169 if (needs_gmac) { 170 id = stmmac_get_id(priv, GMAC_VERSION); 171 } else { 172 id = stmmac_get_id(priv, GMAC4_VERSION); 173 } 174 175 /* Save ID for later use */ 176 priv->synopsys_id = id; 177 178 /* Check for HW specific setup first */ 179 if (priv->plat->setup) { 180 priv->hw = priv->plat->setup(priv); 181 if (!priv->hw) 182 return -ENOMEM; 183 return 0; 184 } 185 186 mac = devm_kzalloc(priv->device, sizeof(*mac), GFP_KERNEL); 187 if (!mac) 188 return -ENOMEM; 189 190 /* Fallback to generic HW */ 191 for (i = ARRAY_SIZE(stmmac_hw) - 1; i >= 0; i--) { 192 entry = &stmmac_hw[i]; 193 194 if (needs_gmac ^ entry->gmac) 195 continue; 196 if (needs_gmac4 ^ entry->gmac4) 197 continue; 198 if (id < entry->min_id) 199 continue; 200 201 mac->desc = entry->desc; 202 mac->dma = entry->dma; 203 mac->mac = entry->mac; 204 mac->ptp = entry->hwtimestamp; 205 mac->mode = entry->mode; 206 mac->tc = entry->tc; 207 208 priv->hw = mac; 209 210 /* Entry found */ 211 ret = entry->setup(priv); 212 if (ret) 213 return ret; 214 215 /* Run quirks, if needed */ 216 if (entry->quirks) { 217 ret = entry->quirks(priv); 218 if (ret) 219 return ret; 220 } 221 222 return 0; 223 } 224 225 dev_err(priv->device, "Failed to find HW IF (id=0x%x, gmac=%d/%d)\n", 226 id, needs_gmac, needs_gmac4); 227 return -EINVAL; 228 } 229