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