1 /* 2 * Driver for (BCM4706)? GBit MAC core on BCMA bus. 3 * 4 * Copyright (C) 2012 Rafał Miłecki <zajec5@gmail.com> 5 * 6 * Licensed under the GNU/GPL. See COPYING for details. 7 */ 8 9 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 10 11 #include <linux/bcma/bcma.h> 12 #include <linux/brcmphy.h> 13 #include <linux/etherdevice.h> 14 #include <linux/of_net.h> 15 #include "bgmac.h" 16 17 static inline bool bgmac_is_bcm4707_family(struct bcma_device *core) 18 { 19 switch (core->bus->chipinfo.id) { 20 case BCMA_CHIP_ID_BCM4707: 21 case BCMA_CHIP_ID_BCM47094: 22 case BCMA_CHIP_ID_BCM53018: 23 return true; 24 default: 25 return false; 26 } 27 } 28 29 /************************************************** 30 * BCMA bus ops 31 **************************************************/ 32 33 static u32 bcma_bgmac_read(struct bgmac *bgmac, u16 offset) 34 { 35 return bcma_read32(bgmac->bcma.core, offset); 36 } 37 38 static void bcma_bgmac_write(struct bgmac *bgmac, u16 offset, u32 value) 39 { 40 bcma_write32(bgmac->bcma.core, offset, value); 41 } 42 43 static u32 bcma_bgmac_idm_read(struct bgmac *bgmac, u16 offset) 44 { 45 return bcma_aread32(bgmac->bcma.core, offset); 46 } 47 48 static void bcma_bgmac_idm_write(struct bgmac *bgmac, u16 offset, u32 value) 49 { 50 return bcma_awrite32(bgmac->bcma.core, offset, value); 51 } 52 53 static bool bcma_bgmac_clk_enabled(struct bgmac *bgmac) 54 { 55 return bcma_core_is_enabled(bgmac->bcma.core); 56 } 57 58 static void bcma_bgmac_clk_enable(struct bgmac *bgmac, u32 flags) 59 { 60 bcma_core_enable(bgmac->bcma.core, flags); 61 } 62 63 static void bcma_bgmac_cco_ctl_maskset(struct bgmac *bgmac, u32 offset, 64 u32 mask, u32 set) 65 { 66 struct bcma_drv_cc *cc = &bgmac->bcma.core->bus->drv_cc; 67 68 bcma_chipco_chipctl_maskset(cc, offset, mask, set); 69 } 70 71 static u32 bcma_bgmac_get_bus_clock(struct bgmac *bgmac) 72 { 73 struct bcma_drv_cc *cc = &bgmac->bcma.core->bus->drv_cc; 74 75 return bcma_pmu_get_bus_clock(cc); 76 } 77 78 static void bcma_bgmac_cmn_maskset32(struct bgmac *bgmac, u16 offset, u32 mask, 79 u32 set) 80 { 81 bcma_maskset32(bgmac->bcma.cmn, offset, mask, set); 82 } 83 84 static int bcma_phy_connect(struct bgmac *bgmac) 85 { 86 struct phy_device *phy_dev; 87 char bus_id[MII_BUS_ID_SIZE + 3]; 88 89 /* Connect to the PHY */ 90 snprintf(bus_id, sizeof(bus_id), PHY_ID_FMT, bgmac->mii_bus->id, 91 bgmac->phyaddr); 92 phy_dev = phy_connect(bgmac->net_dev, bus_id, bgmac_adjust_link, 93 PHY_INTERFACE_MODE_MII); 94 if (IS_ERR(phy_dev)) { 95 dev_err(bgmac->dev, "PHY connection failed\n"); 96 return PTR_ERR(phy_dev); 97 } 98 99 return 0; 100 } 101 102 static const struct bcma_device_id bgmac_bcma_tbl[] = { 103 BCMA_CORE(BCMA_MANUF_BCM, BCMA_CORE_4706_MAC_GBIT, 104 BCMA_ANY_REV, BCMA_ANY_CLASS), 105 BCMA_CORE(BCMA_MANUF_BCM, BCMA_CORE_MAC_GBIT, BCMA_ANY_REV, 106 BCMA_ANY_CLASS), 107 {}, 108 }; 109 MODULE_DEVICE_TABLE(bcma, bgmac_bcma_tbl); 110 111 /* http://bcm-v4.sipsolutions.net/mac-gbit/gmac/chipattach */ 112 static int bgmac_probe(struct bcma_device *core) 113 { 114 struct bcma_chipinfo *ci = &core->bus->chipinfo; 115 struct ssb_sprom *sprom = &core->bus->sprom; 116 struct mii_bus *mii_bus; 117 struct bgmac *bgmac; 118 const u8 *mac = NULL; 119 int err; 120 121 bgmac = bgmac_alloc(&core->dev); 122 if (!bgmac) 123 return -ENOMEM; 124 125 bgmac->bcma.core = core; 126 bgmac->dma_dev = core->dma_dev; 127 bgmac->irq = core->irq; 128 129 bcma_set_drvdata(core, bgmac); 130 131 if (bgmac->dev->of_node) 132 mac = of_get_mac_address(bgmac->dev->of_node); 133 134 /* If no MAC address assigned via device tree, check SPROM */ 135 if (IS_ERR_OR_NULL(mac)) { 136 switch (core->core_unit) { 137 case 0: 138 mac = sprom->et0mac; 139 break; 140 case 1: 141 mac = sprom->et1mac; 142 break; 143 case 2: 144 mac = sprom->et2mac; 145 break; 146 default: 147 dev_err(bgmac->dev, "Unsupported core_unit %d\n", 148 core->core_unit); 149 err = -ENOTSUPP; 150 goto err; 151 } 152 } 153 154 ether_addr_copy(bgmac->net_dev->dev_addr, mac); 155 156 /* On BCM4706 we need common core to access PHY */ 157 if (core->id.id == BCMA_CORE_4706_MAC_GBIT && 158 !core->bus->drv_gmac_cmn.core) { 159 dev_err(bgmac->dev, "GMAC CMN core not found (required for BCM4706)\n"); 160 err = -ENODEV; 161 goto err; 162 } 163 bgmac->bcma.cmn = core->bus->drv_gmac_cmn.core; 164 165 switch (core->core_unit) { 166 case 0: 167 bgmac->phyaddr = sprom->et0phyaddr; 168 break; 169 case 1: 170 bgmac->phyaddr = sprom->et1phyaddr; 171 break; 172 case 2: 173 bgmac->phyaddr = sprom->et2phyaddr; 174 break; 175 } 176 bgmac->phyaddr &= BGMAC_PHY_MASK; 177 if (bgmac->phyaddr == BGMAC_PHY_MASK) { 178 dev_err(bgmac->dev, "No PHY found\n"); 179 err = -ENODEV; 180 goto err; 181 } 182 dev_info(bgmac->dev, "Found PHY addr: %d%s\n", bgmac->phyaddr, 183 bgmac->phyaddr == BGMAC_PHY_NOREGS ? " (NOREGS)" : ""); 184 185 if (!bgmac_is_bcm4707_family(core) && 186 !(ci->id == BCMA_CHIP_ID_BCM53573 && core->core_unit == 1)) { 187 struct phy_device *phydev; 188 189 mii_bus = bcma_mdio_mii_register(bgmac); 190 if (IS_ERR(mii_bus)) { 191 err = PTR_ERR(mii_bus); 192 goto err; 193 } 194 bgmac->mii_bus = mii_bus; 195 196 phydev = mdiobus_get_phy(bgmac->mii_bus, bgmac->phyaddr); 197 if (ci->id == BCMA_CHIP_ID_BCM53573 && phydev && 198 (phydev->drv->phy_id & phydev->drv->phy_id_mask) == PHY_ID_BCM54210E) 199 phydev->dev_flags |= PHY_BRCM_EN_MASTER_MODE; 200 } 201 202 if (core->bus->hosttype == BCMA_HOSTTYPE_PCI) { 203 dev_err(bgmac->dev, "PCI setup not implemented\n"); 204 err = -ENOTSUPP; 205 goto err1; 206 } 207 208 bgmac->has_robosw = !!(sprom->boardflags_lo & BGMAC_BFL_ENETROBO); 209 if (bgmac->has_robosw) 210 dev_warn(bgmac->dev, "Support for Roboswitch not implemented\n"); 211 212 if (sprom->boardflags_lo & BGMAC_BFL_ENETADM) 213 dev_warn(bgmac->dev, "Support for ADMtek ethernet switch not implemented\n"); 214 215 /* Feature Flags */ 216 switch (ci->id) { 217 /* BCM 471X/535X family */ 218 case BCMA_CHIP_ID_BCM4716: 219 bgmac->feature_flags |= BGMAC_FEAT_CLKCTLST; 220 /* fallthrough */ 221 case BCMA_CHIP_ID_BCM47162: 222 bgmac->feature_flags |= BGMAC_FEAT_FLW_CTRL2; 223 bgmac->feature_flags |= BGMAC_FEAT_SET_RXQ_CLK; 224 break; 225 case BCMA_CHIP_ID_BCM5357: 226 case BCMA_CHIP_ID_BCM53572: 227 bgmac->feature_flags |= BGMAC_FEAT_SET_RXQ_CLK; 228 bgmac->feature_flags |= BGMAC_FEAT_CLKCTLST; 229 bgmac->feature_flags |= BGMAC_FEAT_FLW_CTRL1; 230 bgmac->feature_flags |= BGMAC_FEAT_SW_TYPE_PHY; 231 if (ci->pkg == BCMA_PKG_ID_BCM47188 || 232 ci->pkg == BCMA_PKG_ID_BCM47186) { 233 bgmac->feature_flags |= BGMAC_FEAT_SW_TYPE_RGMII; 234 bgmac->feature_flags |= BGMAC_FEAT_IOST_ATTACHED; 235 } 236 if (ci->pkg == BCMA_PKG_ID_BCM5358) 237 bgmac->feature_flags |= BGMAC_FEAT_SW_TYPE_EPHYRMII; 238 break; 239 case BCMA_CHIP_ID_BCM53573: 240 bgmac->feature_flags |= BGMAC_FEAT_CLKCTLST; 241 bgmac->feature_flags |= BGMAC_FEAT_SET_RXQ_CLK; 242 if (ci->pkg == BCMA_PKG_ID_BCM47189) 243 bgmac->feature_flags |= BGMAC_FEAT_IOST_ATTACHED; 244 if (core->core_unit == 0) { 245 bgmac->feature_flags |= BGMAC_FEAT_CC4_IF_SW_TYPE; 246 if (ci->pkg == BCMA_PKG_ID_BCM47189) 247 bgmac->feature_flags |= 248 BGMAC_FEAT_CC4_IF_SW_TYPE_RGMII; 249 } else if (core->core_unit == 1) { 250 bgmac->feature_flags |= BGMAC_FEAT_IRQ_ID_OOB_6; 251 bgmac->feature_flags |= BGMAC_FEAT_CC7_IF_TYPE_RGMII; 252 } 253 break; 254 case BCMA_CHIP_ID_BCM4749: 255 bgmac->feature_flags |= BGMAC_FEAT_SET_RXQ_CLK; 256 bgmac->feature_flags |= BGMAC_FEAT_CLKCTLST; 257 bgmac->feature_flags |= BGMAC_FEAT_FLW_CTRL1; 258 bgmac->feature_flags |= BGMAC_FEAT_SW_TYPE_PHY; 259 if (ci->pkg == 10) { 260 bgmac->feature_flags |= BGMAC_FEAT_SW_TYPE_RGMII; 261 bgmac->feature_flags |= BGMAC_FEAT_IOST_ATTACHED; 262 } 263 break; 264 /* bcm4707_family */ 265 case BCMA_CHIP_ID_BCM4707: 266 case BCMA_CHIP_ID_BCM47094: 267 case BCMA_CHIP_ID_BCM53018: 268 bgmac->feature_flags |= BGMAC_FEAT_CLKCTLST; 269 bgmac->feature_flags |= BGMAC_FEAT_NO_RESET; 270 bgmac->feature_flags |= BGMAC_FEAT_FORCE_SPEED_2500; 271 break; 272 default: 273 bgmac->feature_flags |= BGMAC_FEAT_CLKCTLST; 274 bgmac->feature_flags |= BGMAC_FEAT_SET_RXQ_CLK; 275 } 276 277 if (!bgmac_is_bcm4707_family(core) && core->id.rev > 2) 278 bgmac->feature_flags |= BGMAC_FEAT_MISC_PLL_REQ; 279 280 if (core->id.id == BCMA_CORE_4706_MAC_GBIT) { 281 bgmac->feature_flags |= BGMAC_FEAT_CMN_PHY_CTL; 282 bgmac->feature_flags |= BGMAC_FEAT_NO_CLR_MIB; 283 } 284 285 if (core->id.rev >= 4) { 286 bgmac->feature_flags |= BGMAC_FEAT_CMDCFG_SR_REV4; 287 bgmac->feature_flags |= BGMAC_FEAT_TX_MASK_SETUP; 288 bgmac->feature_flags |= BGMAC_FEAT_RX_MASK_SETUP; 289 } 290 291 bgmac->read = bcma_bgmac_read; 292 bgmac->write = bcma_bgmac_write; 293 bgmac->idm_read = bcma_bgmac_idm_read; 294 bgmac->idm_write = bcma_bgmac_idm_write; 295 bgmac->clk_enabled = bcma_bgmac_clk_enabled; 296 bgmac->clk_enable = bcma_bgmac_clk_enable; 297 bgmac->cco_ctl_maskset = bcma_bgmac_cco_ctl_maskset; 298 bgmac->get_bus_clock = bcma_bgmac_get_bus_clock; 299 bgmac->cmn_maskset32 = bcma_bgmac_cmn_maskset32; 300 if (bgmac->mii_bus) 301 bgmac->phy_connect = bcma_phy_connect; 302 else 303 bgmac->phy_connect = bgmac_phy_connect_direct; 304 305 err = bgmac_enet_probe(bgmac); 306 if (err) 307 goto err1; 308 309 return 0; 310 311 err1: 312 bcma_mdio_mii_unregister(bgmac->mii_bus); 313 err: 314 bcma_set_drvdata(core, NULL); 315 316 return err; 317 } 318 319 static void bgmac_remove(struct bcma_device *core) 320 { 321 struct bgmac *bgmac = bcma_get_drvdata(core); 322 323 bcma_mdio_mii_unregister(bgmac->mii_bus); 324 bgmac_enet_remove(bgmac); 325 bcma_set_drvdata(core, NULL); 326 kfree(bgmac); 327 } 328 329 static struct bcma_driver bgmac_bcma_driver = { 330 .name = KBUILD_MODNAME, 331 .id_table = bgmac_bcma_tbl, 332 .probe = bgmac_probe, 333 .remove = bgmac_remove, 334 }; 335 336 static int __init bgmac_init(void) 337 { 338 int err; 339 340 err = bcma_driver_register(&bgmac_bcma_driver); 341 if (err) 342 return err; 343 pr_info("Broadcom 47xx GBit MAC driver loaded\n"); 344 345 return 0; 346 } 347 348 static void __exit bgmac_exit(void) 349 { 350 bcma_driver_unregister(&bgmac_bcma_driver); 351 } 352 353 module_init(bgmac_init) 354 module_exit(bgmac_exit) 355 356 MODULE_AUTHOR("Rafał Miłecki"); 357 MODULE_LICENSE("GPL"); 358