1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * DWMAC glue driver for Motorcomm PCI Ethernet controllers 4 * 5 * Copyright (c) 2025-2026 Yao Zi <me@ziyao.cc> 6 */ 7 8 #include <linux/bits.h> 9 #include <linux/dev_printk.h> 10 #include <linux/io.h> 11 #include <linux/iopoll.h> 12 #include <linux/module.h> 13 #include <linux/pci.h> 14 #include <linux/slab.h> 15 #include <linux/stmmac.h> 16 17 #include "dwmac4.h" 18 #include "stmmac.h" 19 #include "stmmac_libpci.h" 20 21 #define DRIVER_NAME "dwmac-motorcomm" 22 23 #define PCI_VENDOR_ID_MOTORCOMM 0x1f0a 24 25 /* Register definition */ 26 #define EPHY_CTRL 0x1004 27 /* Clearing this bit asserts resets for internal MDIO bus and PHY */ 28 #define EPHY_MDIO_PHY_RESET BIT(0) 29 #define OOB_WOL_CTRL 0x1010 30 #define OOB_WOL_CTRL_DIS BIT(0) 31 #define MGMT_INT_CTRL0 0x1100 32 #define INT_MODERATION 0x1108 33 #define INT_MODERATION_RX GENMASK(11, 0) 34 #define INT_MODERATION_TX GENMASK(27, 16) 35 #define EFUSE_OP_CTRL_0 0x1500 36 #define EFUSE_OP_MODE GENMASK(1, 0) 37 #define EFUSE_OP_ROW_READ 0x1 38 #define EFUSE_OP_START BIT(2) 39 #define EFUSE_OP_ADDR GENMASK(15, 8) 40 #define EFUSE_OP_CTRL_1 0x1504 41 #define EFUSE_OP_DONE BIT(1) 42 #define EFUSE_OP_RD_DATA GENMASK(31, 24) 43 #define SYS_RESET 0x152c 44 #define SYS_RESET_RESET BIT(31) 45 #define GMAC_OFFSET 0x2000 46 47 /* Constants */ 48 #define EFUSE_READ_TIMEOUT_US 20000 49 #define EFUSE_PATCH_REGION_OFFSET 18 50 #define EFUSE_PATCH_MAX_NUM 39 51 #define EFUSE_ADDR_MACA0LR 0x1520 52 #define EFUSE_ADDR_MACA0HR 0x1524 53 54 struct motorcomm_efuse_patch { 55 __le16 addr; 56 __le32 data; 57 } __packed; 58 59 struct dwmac_motorcomm_priv { 60 void __iomem *base; 61 }; 62 63 static int motorcomm_efuse_read_byte(struct dwmac_motorcomm_priv *priv, 64 u8 offset, u8 *byte) 65 { 66 u32 reg; 67 int ret; 68 69 writel(FIELD_PREP(EFUSE_OP_MODE, EFUSE_OP_ROW_READ) | 70 FIELD_PREP(EFUSE_OP_ADDR, offset) | 71 EFUSE_OP_START, priv->base + EFUSE_OP_CTRL_0); 72 73 ret = readl_poll_timeout(priv->base + EFUSE_OP_CTRL_1, 74 reg, reg & EFUSE_OP_DONE, 2000, 75 EFUSE_READ_TIMEOUT_US); 76 77 *byte = FIELD_GET(EFUSE_OP_RD_DATA, reg); 78 79 return ret; 80 } 81 82 static int motorcomm_efuse_read_patch(struct dwmac_motorcomm_priv *priv, 83 u8 index, 84 struct motorcomm_efuse_patch *patch) 85 { 86 u8 *p = (u8 *)patch, offset; 87 int i, ret; 88 89 for (i = 0; i < sizeof(*patch); i++) { 90 offset = EFUSE_PATCH_REGION_OFFSET + sizeof(*patch) * index + i; 91 92 ret = motorcomm_efuse_read_byte(priv, offset, &p[i]); 93 if (ret) 94 return ret; 95 } 96 97 return 0; 98 } 99 100 static int motorcomm_efuse_get_patch_value(struct dwmac_motorcomm_priv *priv, 101 u16 addr, u32 *value) 102 { 103 struct motorcomm_efuse_patch patch; 104 int i, ret; 105 106 for (i = 0; i < EFUSE_PATCH_MAX_NUM; i++) { 107 ret = motorcomm_efuse_read_patch(priv, i, &patch); 108 if (ret) 109 return ret; 110 111 if (patch.addr == 0) { 112 return -ENOENT; 113 } else if (le16_to_cpu(patch.addr) == addr) { 114 *value = le32_to_cpu(patch.data); 115 return 0; 116 } 117 } 118 119 return -ENOENT; 120 } 121 122 static int motorcomm_efuse_read_mac(struct device *dev, 123 struct dwmac_motorcomm_priv *priv, u8 *mac) 124 { 125 u32 maca0lr, maca0hr; 126 int ret; 127 128 ret = motorcomm_efuse_get_patch_value(priv, EFUSE_ADDR_MACA0LR, 129 &maca0lr); 130 if (ret) 131 return dev_err_probe(dev, ret, 132 "failed to read maca0lr from eFuse\n"); 133 134 ret = motorcomm_efuse_get_patch_value(priv, EFUSE_ADDR_MACA0HR, 135 &maca0hr); 136 if (ret) 137 return dev_err_probe(dev, ret, 138 "failed to read maca0hr from eFuse\n"); 139 140 mac[0] = FIELD_GET(GENMASK(15, 8), maca0hr); 141 mac[1] = FIELD_GET(GENMASK(7, 0), maca0hr); 142 mac[2] = FIELD_GET(GENMASK(31, 24), maca0lr); 143 mac[3] = FIELD_GET(GENMASK(23, 16), maca0lr); 144 mac[4] = FIELD_GET(GENMASK(15, 8), maca0lr); 145 mac[5] = FIELD_GET(GENMASK(7, 0), maca0lr); 146 147 return 0; 148 } 149 150 static void motorcomm_deassert_mdio_phy_reset(struct dwmac_motorcomm_priv *priv) 151 { 152 u32 reg = readl(priv->base + EPHY_CTRL); 153 154 reg |= EPHY_MDIO_PHY_RESET; 155 156 writel(reg, priv->base + EPHY_CTRL); 157 } 158 159 static void motorcomm_reset(struct dwmac_motorcomm_priv *priv) 160 { 161 u32 reg = readl(priv->base + SYS_RESET); 162 163 reg &= ~SYS_RESET_RESET; 164 writel(reg, priv->base + SYS_RESET); 165 166 reg |= SYS_RESET_RESET; 167 writel(reg, priv->base + SYS_RESET); 168 169 motorcomm_deassert_mdio_phy_reset(priv); 170 } 171 172 static void motorcomm_init(struct dwmac_motorcomm_priv *priv) 173 { 174 writel(0x0, priv->base + MGMT_INT_CTRL0); 175 176 writel(FIELD_PREP(INT_MODERATION_RX, 200) | 177 FIELD_PREP(INT_MODERATION_TX, 200), 178 priv->base + INT_MODERATION); 179 180 /* 181 * OOB WOL must be disabled during normal operation, or DMA interrupts 182 * cannot be delivered to the host. 183 */ 184 writel(OOB_WOL_CTRL_DIS, priv->base + OOB_WOL_CTRL); 185 } 186 187 static int motorcomm_resume(struct device *dev, void *bsp_priv) 188 { 189 struct dwmac_motorcomm_priv *priv = bsp_priv; 190 int ret; 191 192 ret = stmmac_pci_plat_resume(dev, bsp_priv); 193 if (ret) 194 return ret; 195 196 /* 197 * When recovering from D3hot, EPHY_MDIO_PHY_RESET is automatically 198 * asserted, and must be deasserted for normal operation. 199 */ 200 motorcomm_deassert_mdio_phy_reset(priv); 201 motorcomm_init(priv); 202 203 return 0; 204 } 205 206 static struct plat_stmmacenet_data * 207 motorcomm_default_plat_data(struct pci_dev *pdev) 208 { 209 struct plat_stmmacenet_data *plat; 210 struct device *dev = &pdev->dev; 211 212 plat = stmmac_plat_dat_alloc(dev); 213 if (!plat) 214 return NULL; 215 216 plat->mdio_bus_data = devm_kzalloc(dev, sizeof(*plat->mdio_bus_data), 217 GFP_KERNEL); 218 if (!plat->mdio_bus_data) 219 return NULL; 220 221 plat->dma_cfg = devm_kzalloc(dev, sizeof(*plat->dma_cfg), GFP_KERNEL); 222 if (!plat->dma_cfg) 223 return NULL; 224 225 plat->axi = devm_kzalloc(dev, sizeof(*plat->axi), GFP_KERNEL); 226 if (!plat->axi) 227 return NULL; 228 229 plat->dma_cfg->pbl = DEFAULT_DMA_PBL; 230 plat->dma_cfg->pblx8 = true; 231 plat->dma_cfg->txpbl = 32; 232 plat->dma_cfg->rxpbl = 32; 233 plat->dma_cfg->eame = true; 234 plat->dma_cfg->mixed_burst = true; 235 236 plat->axi->axi_wr_osr_lmt = 1; 237 plat->axi->axi_rd_osr_lmt = 1; 238 plat->axi->axi_mb = true; 239 plat->axi->axi_blen_regval = DMA_AXI_BLEN4 | DMA_AXI_BLEN8 | 240 DMA_AXI_BLEN16 | DMA_AXI_BLEN32; 241 242 plat->bus_id = pci_dev_id(pdev); 243 plat->phy_interface = PHY_INTERFACE_MODE_GMII; 244 /* 245 * YT6801 requires an 25MHz clock input/oscillator to function, which 246 * is likely the source of CSR clock. 247 */ 248 plat->clk_csr = STMMAC_CSR_20_35M; 249 plat->tx_coe = 1; 250 plat->rx_coe = 1; 251 plat->clk_ref_rate = 125000000; 252 plat->core_type = DWMAC_CORE_GMAC4; 253 plat->suspend = stmmac_pci_plat_suspend; 254 plat->resume = motorcomm_resume; 255 plat->flags = STMMAC_FLAG_TSO_EN | 256 STMMAC_FLAG_EN_TX_LPI_CLK_PHY_CAP; 257 258 return plat; 259 } 260 261 static void motorcomm_free_irq(void *data) 262 { 263 struct pci_dev *pdev = data; 264 265 pci_free_irq_vectors(pdev); 266 } 267 268 static int motorcomm_setup_irq(struct pci_dev *pdev, 269 struct stmmac_resources *res, 270 struct plat_stmmacenet_data *plat) 271 { 272 int ret; 273 274 ret = pci_alloc_irq_vectors(pdev, 6, 6, PCI_IRQ_MSIX); 275 if (ret > 0) { 276 res->rx_irq[0] = pci_irq_vector(pdev, 0); 277 res->tx_irq[0] = pci_irq_vector(pdev, 4); 278 res->irq = pci_irq_vector(pdev, 5); 279 280 plat->flags |= STMMAC_FLAG_MULTI_MSI_EN; 281 } else { 282 dev_info(&pdev->dev, "failed to allocate MSI-X vector: %d\n", 283 ret); 284 dev_info(&pdev->dev, "try MSI instead\n"); 285 286 ret = pci_alloc_irq_vectors(pdev, 1, 1, PCI_IRQ_MSI); 287 if (ret < 0) 288 return dev_err_probe(&pdev->dev, ret, 289 "failed to allocate MSI\n"); 290 291 res->irq = pci_irq_vector(pdev, 0); 292 } 293 294 return devm_add_action_or_reset(&pdev->dev, motorcomm_free_irq, pdev); 295 } 296 297 static int motorcomm_probe(struct pci_dev *pdev, const struct pci_device_id *id) 298 { 299 struct plat_stmmacenet_data *plat; 300 struct dwmac_motorcomm_priv *priv; 301 struct stmmac_resources res = {}; 302 int ret; 303 304 priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); 305 if (!priv) 306 return -ENOMEM; 307 308 plat = motorcomm_default_plat_data(pdev); 309 if (!plat) 310 return -ENOMEM; 311 312 plat->bsp_priv = priv; 313 314 ret = pcim_enable_device(pdev); 315 if (ret) 316 return dev_err_probe(&pdev->dev, ret, 317 "failed to enable device\n"); 318 319 priv->base = pcim_iomap_region(pdev, 0, DRIVER_NAME); 320 if (IS_ERR(priv->base)) 321 return dev_err_probe(&pdev->dev, PTR_ERR(priv->base), 322 "failed to map IO region\n"); 323 324 pci_set_master(pdev); 325 326 /* 327 * Some PCIe addons cards based on YT6801 don't deliver MSI(X) with ASPM 328 * enabled. Sadly there isn't a reliable way to read out OEM of the 329 * card, so let's disable L1 state unconditionally for safety. 330 */ 331 ret = pci_disable_link_state(pdev, PCIE_LINK_STATE_L1); 332 if (ret) 333 dev_warn(&pdev->dev, "failed to disable L1 state: %d\n", ret); 334 335 motorcomm_reset(priv); 336 337 ret = motorcomm_efuse_read_mac(&pdev->dev, priv, res.mac); 338 if (ret == -ENOENT) { 339 dev_warn(&pdev->dev, "eFuse contains no valid MAC address\n"); 340 dev_warn(&pdev->dev, "fallback to random MAC address\n"); 341 342 eth_random_addr(res.mac); 343 } else if (ret) { 344 return dev_err_probe(&pdev->dev, ret, 345 "failed to read MAC address from eFuse\n"); 346 } 347 348 ret = motorcomm_setup_irq(pdev, &res, plat); 349 if (ret) 350 return dev_err_probe(&pdev->dev, ret, "failed to setup IRQ\n"); 351 352 motorcomm_init(priv); 353 354 res.addr = priv->base + GMAC_OFFSET; 355 356 return stmmac_dvr_probe(&pdev->dev, plat, &res); 357 } 358 359 static void motorcomm_remove(struct pci_dev *pdev) 360 { 361 stmmac_dvr_remove(&pdev->dev); 362 } 363 364 static const struct pci_device_id dwmac_motorcomm_pci_id_table[] = { 365 { PCI_DEVICE(PCI_VENDOR_ID_MOTORCOMM, 0x6801) }, 366 { }, 367 }; 368 MODULE_DEVICE_TABLE(pci, dwmac_motorcomm_pci_id_table); 369 370 static struct pci_driver dwmac_motorcomm_pci_driver = { 371 .name = DRIVER_NAME, 372 .id_table = dwmac_motorcomm_pci_id_table, 373 .probe = motorcomm_probe, 374 .remove = motorcomm_remove, 375 .driver = { 376 .pm = &stmmac_simple_pm_ops, 377 }, 378 }; 379 380 module_pci_driver(dwmac_motorcomm_pci_driver); 381 382 MODULE_DESCRIPTION("DWMAC glue driver for Motorcomm PCI Ethernet controllers"); 383 MODULE_AUTHOR("Yao Zi <me@ziyao.cc>"); 384 MODULE_LICENSE("GPL"); 385