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 17static 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 33static u32 bcma_bgmac_read(struct bgmac *bgmac, u16 offset) 34{ 35 return bcma_read32(bgmac->bcma.core, offset); 36} 37 38static void bcma_bgmac_write(struct bgmac *bgmac, u16 offset, u32 value) 39{ 40 bcma_write32(bgmac->bcma.core, offset, value); 41} 42 43static u32 bcma_bgmac_idm_read(struct bgmac *bgmac, u16 offset) 44{ 45 return bcma_aread32(bgmac->bcma.core, offset); 46} 47 48static void bcma_bgmac_idm_write(struct bgmac *bgmac, u16 offset, u32 value) 49{ 50 return bcma_awrite32(bgmac->bcma.core, offset, value); 51} 52 53static bool bcma_bgmac_clk_enabled(struct bgmac *bgmac) 54{ 55 return bcma_core_is_enabled(bgmac->bcma.core); 56} 57 58static void bcma_bgmac_clk_enable(struct bgmac *bgmac, u32 flags) 59{ 60 bcma_core_enable(bgmac->bcma.core, flags); 61} 62 63static 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 71static 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 78static 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 84static 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 102static 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}; 109MODULE_DEVICE_TABLE(bcma, bgmac_bcma_tbl); 110 111/* http://bcm-v4.sipsolutions.net/mac-gbit/gmac/chipattach */ 112static 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->id == BCMA_CHIP_ID_BCM5357 && ci->pkg == BCMA_PKG_ID_BCM47186) || 232 (ci->id == BCMA_CHIP_ID_BCM53572 && ci->pkg == BCMA_PKG_ID_BCM47188)) { 233 bgmac->feature_flags |= BGMAC_FEAT_SW_TYPE_RGMII; 234 bgmac->feature_flags |= BGMAC_FEAT_IOST_ATTACHED; 235 } 236 if (ci->id == BCMA_CHIP_ID_BCM5357 && 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 311err1: 312 bcma_mdio_mii_unregister(bgmac->mii_bus); 313err: 314 bcma_set_drvdata(core, NULL); 315 316 return err; 317} 318 319static 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} 327 328static struct bcma_driver bgmac_bcma_driver = { 329 .name = KBUILD_MODNAME, 330 .id_table = bgmac_bcma_tbl, 331 .probe = bgmac_probe, 332 .remove = bgmac_remove, 333}; 334 335static int __init bgmac_init(void) 336{ 337 int err; 338 339 err = bcma_driver_register(&bgmac_bcma_driver); 340 if (err) 341 return err; 342 pr_info("Broadcom 47xx GBit MAC driver loaded\n"); 343 344 return 0; 345} 346 347static void __exit bgmac_exit(void) 348{ 349 bcma_driver_unregister(&bgmac_bcma_driver); 350} 351 352module_init(bgmac_init) 353module_exit(bgmac_exit) 354 355MODULE_AUTHOR("Rafał Miłecki"); 356MODULE_LICENSE("GPL"); 357