Back to home page

OSCL-LXR

 
 

    


0001 /*
0002  * Driver for (BCM4706)? GBit MAC core on BCMA bus.
0003  *
0004  * Copyright (C) 2012 Rafał Miłecki <zajec5@gmail.com>
0005  *
0006  * Licensed under the GNU/GPL. See COPYING for details.
0007  */
0008 
0009 #define pr_fmt(fmt)     KBUILD_MODNAME ": " fmt
0010 
0011 #include <linux/bcma/bcma.h>
0012 #include <linux/brcmphy.h>
0013 #include <linux/of_mdio.h>
0014 #include "bgmac.h"
0015 
0016 static bool bcma_mdio_wait_value(struct bcma_device *core, u16 reg, u32 mask,
0017                  u32 value, int timeout)
0018 {
0019     u32 val;
0020     int i;
0021 
0022     for (i = 0; i < timeout / 10; i++) {
0023         val = bcma_read32(core, reg);
0024         if ((val & mask) == value)
0025             return true;
0026         udelay(10);
0027     }
0028     dev_err(&core->dev, "Timeout waiting for reg 0x%X\n", reg);
0029     return false;
0030 }
0031 
0032 /**************************************************
0033  * PHY ops
0034  **************************************************/
0035 
0036 static u16 bcma_mdio_phy_read(struct bgmac *bgmac, u8 phyaddr, u8 reg)
0037 {
0038     struct bcma_device *core;
0039     u16 phy_access_addr;
0040     u16 phy_ctl_addr;
0041     u32 tmp;
0042 
0043     BUILD_BUG_ON(BGMAC_PA_DATA_MASK != BCMA_GMAC_CMN_PA_DATA_MASK);
0044     BUILD_BUG_ON(BGMAC_PA_ADDR_MASK != BCMA_GMAC_CMN_PA_ADDR_MASK);
0045     BUILD_BUG_ON(BGMAC_PA_ADDR_SHIFT != BCMA_GMAC_CMN_PA_ADDR_SHIFT);
0046     BUILD_BUG_ON(BGMAC_PA_REG_MASK != BCMA_GMAC_CMN_PA_REG_MASK);
0047     BUILD_BUG_ON(BGMAC_PA_REG_SHIFT != BCMA_GMAC_CMN_PA_REG_SHIFT);
0048     BUILD_BUG_ON(BGMAC_PA_WRITE != BCMA_GMAC_CMN_PA_WRITE);
0049     BUILD_BUG_ON(BGMAC_PA_START != BCMA_GMAC_CMN_PA_START);
0050     BUILD_BUG_ON(BGMAC_PC_EPA_MASK != BCMA_GMAC_CMN_PC_EPA_MASK);
0051     BUILD_BUG_ON(BGMAC_PC_MCT_MASK != BCMA_GMAC_CMN_PC_MCT_MASK);
0052     BUILD_BUG_ON(BGMAC_PC_MCT_SHIFT != BCMA_GMAC_CMN_PC_MCT_SHIFT);
0053     BUILD_BUG_ON(BGMAC_PC_MTE != BCMA_GMAC_CMN_PC_MTE);
0054 
0055     if (bgmac->bcma.core->id.id == BCMA_CORE_4706_MAC_GBIT) {
0056         core = bgmac->bcma.core->bus->drv_gmac_cmn.core;
0057         phy_access_addr = BCMA_GMAC_CMN_PHY_ACCESS;
0058         phy_ctl_addr = BCMA_GMAC_CMN_PHY_CTL;
0059     } else {
0060         core = bgmac->bcma.core;
0061         phy_access_addr = BGMAC_PHY_ACCESS;
0062         phy_ctl_addr = BGMAC_PHY_CNTL;
0063     }
0064 
0065     tmp = bcma_read32(core, phy_ctl_addr);
0066     tmp &= ~BGMAC_PC_EPA_MASK;
0067     tmp |= phyaddr;
0068     bcma_write32(core, phy_ctl_addr, tmp);
0069 
0070     tmp = BGMAC_PA_START;
0071     tmp |= phyaddr << BGMAC_PA_ADDR_SHIFT;
0072     tmp |= reg << BGMAC_PA_REG_SHIFT;
0073     bcma_write32(core, phy_access_addr, tmp);
0074 
0075     if (!bcma_mdio_wait_value(core, phy_access_addr, BGMAC_PA_START, 0,
0076                   1000)) {
0077         dev_err(&core->dev, "Reading PHY %d register 0x%X failed\n",
0078             phyaddr, reg);
0079         return 0xffff;
0080     }
0081 
0082     return bcma_read32(core, phy_access_addr) & BGMAC_PA_DATA_MASK;
0083 }
0084 
0085 /* http://bcm-v4.sipsolutions.net/mac-gbit/gmac/chipphywr */
0086 static int bcma_mdio_phy_write(struct bgmac *bgmac, u8 phyaddr, u8 reg,
0087                    u16 value)
0088 {
0089     struct bcma_device *core;
0090     u16 phy_access_addr;
0091     u16 phy_ctl_addr;
0092     u32 tmp;
0093 
0094     if (bgmac->bcma.core->id.id == BCMA_CORE_4706_MAC_GBIT) {
0095         core = bgmac->bcma.core->bus->drv_gmac_cmn.core;
0096         phy_access_addr = BCMA_GMAC_CMN_PHY_ACCESS;
0097         phy_ctl_addr = BCMA_GMAC_CMN_PHY_CTL;
0098     } else {
0099         core = bgmac->bcma.core;
0100         phy_access_addr = BGMAC_PHY_ACCESS;
0101         phy_ctl_addr = BGMAC_PHY_CNTL;
0102     }
0103 
0104     tmp = bcma_read32(core, phy_ctl_addr);
0105     tmp &= ~BGMAC_PC_EPA_MASK;
0106     tmp |= phyaddr;
0107     bcma_write32(core, phy_ctl_addr, tmp);
0108 
0109     bcma_write32(bgmac->bcma.core, BGMAC_INT_STATUS, BGMAC_IS_MDIO);
0110     if (bcma_read32(bgmac->bcma.core, BGMAC_INT_STATUS) & BGMAC_IS_MDIO)
0111         dev_warn(&core->dev, "Error setting MDIO int\n");
0112 
0113     tmp = BGMAC_PA_START;
0114     tmp |= BGMAC_PA_WRITE;
0115     tmp |= phyaddr << BGMAC_PA_ADDR_SHIFT;
0116     tmp |= reg << BGMAC_PA_REG_SHIFT;
0117     tmp |= value;
0118     bcma_write32(core, phy_access_addr, tmp);
0119 
0120     if (!bcma_mdio_wait_value(core, phy_access_addr, BGMAC_PA_START, 0,
0121                   1000)) {
0122         dev_err(&core->dev, "Writing to PHY %d register 0x%X failed\n",
0123             phyaddr, reg);
0124         return -ETIMEDOUT;
0125     }
0126 
0127     return 0;
0128 }
0129 
0130 /* http://bcm-v4.sipsolutions.net/mac-gbit/gmac/chipphyinit */
0131 static void bcma_mdio_phy_init(struct bgmac *bgmac)
0132 {
0133     struct bcma_chipinfo *ci = &bgmac->bcma.core->bus->chipinfo;
0134     u8 i;
0135 
0136     /* For some legacy hardware we do chipset-based PHY initialization here
0137      * without even detecting PHY ID. It's hacky and should be cleaned as
0138      * soon as someone can test it.
0139      */
0140     if (ci->id == BCMA_CHIP_ID_BCM5356) {
0141         for (i = 0; i < 5; i++) {
0142             bcma_mdio_phy_write(bgmac, i, 0x1f, 0x008b);
0143             bcma_mdio_phy_write(bgmac, i, 0x15, 0x0100);
0144             bcma_mdio_phy_write(bgmac, i, 0x1f, 0x000f);
0145             bcma_mdio_phy_write(bgmac, i, 0x12, 0x2aaa);
0146             bcma_mdio_phy_write(bgmac, i, 0x1f, 0x000b);
0147         }
0148         return;
0149     }
0150     if ((ci->id == BCMA_CHIP_ID_BCM5357 && ci->pkg != 10) ||
0151         (ci->id == BCMA_CHIP_ID_BCM4749 && ci->pkg != 10) ||
0152         (ci->id == BCMA_CHIP_ID_BCM53572 && ci->pkg != 9)) {
0153         struct bcma_drv_cc *cc = &bgmac->bcma.core->bus->drv_cc;
0154 
0155         bcma_chipco_chipctl_maskset(cc, 2, ~0xc0000000, 0);
0156         bcma_chipco_chipctl_maskset(cc, 4, ~0x80000000, 0);
0157         for (i = 0; i < 5; i++) {
0158             bcma_mdio_phy_write(bgmac, i, 0x1f, 0x000f);
0159             bcma_mdio_phy_write(bgmac, i, 0x16, 0x5284);
0160             bcma_mdio_phy_write(bgmac, i, 0x1f, 0x000b);
0161             bcma_mdio_phy_write(bgmac, i, 0x17, 0x0010);
0162             bcma_mdio_phy_write(bgmac, i, 0x1f, 0x000f);
0163             bcma_mdio_phy_write(bgmac, i, 0x16, 0x5296);
0164             bcma_mdio_phy_write(bgmac, i, 0x17, 0x1073);
0165             bcma_mdio_phy_write(bgmac, i, 0x17, 0x9073);
0166             bcma_mdio_phy_write(bgmac, i, 0x16, 0x52b6);
0167             bcma_mdio_phy_write(bgmac, i, 0x17, 0x9273);
0168             bcma_mdio_phy_write(bgmac, i, 0x1f, 0x000b);
0169         }
0170         return;
0171     }
0172 
0173     /* For all other hw do initialization using PHY subsystem. */
0174     if (bgmac->net_dev && bgmac->net_dev->phydev)
0175         phy_init_hw(bgmac->net_dev->phydev);
0176 }
0177 
0178 /* http://bcm-v4.sipsolutions.net/mac-gbit/gmac/chipphyreset */
0179 static int bcma_mdio_phy_reset(struct mii_bus *bus)
0180 {
0181     struct bgmac *bgmac = bus->priv;
0182     u8 phyaddr = bgmac->phyaddr;
0183 
0184     if (phyaddr == BGMAC_PHY_NOREGS)
0185         return 0;
0186 
0187     bcma_mdio_phy_write(bgmac, phyaddr, MII_BMCR, BMCR_RESET);
0188     udelay(100);
0189     if (bcma_mdio_phy_read(bgmac, phyaddr, MII_BMCR) & BMCR_RESET)
0190         dev_err(bgmac->dev, "PHY reset failed\n");
0191     bcma_mdio_phy_init(bgmac);
0192 
0193     return 0;
0194 }
0195 
0196 /**************************************************
0197  * MII
0198  **************************************************/
0199 
0200 static int bcma_mdio_mii_read(struct mii_bus *bus, int mii_id, int regnum)
0201 {
0202     return bcma_mdio_phy_read(bus->priv, mii_id, regnum);
0203 }
0204 
0205 static int bcma_mdio_mii_write(struct mii_bus *bus, int mii_id, int regnum,
0206                    u16 value)
0207 {
0208     return bcma_mdio_phy_write(bus->priv, mii_id, regnum, value);
0209 }
0210 
0211 struct mii_bus *bcma_mdio_mii_register(struct bgmac *bgmac)
0212 {
0213     struct bcma_device *core = bgmac->bcma.core;
0214     struct mii_bus *mii_bus;
0215     struct device_node *np;
0216     int err;
0217 
0218     mii_bus = mdiobus_alloc();
0219     if (!mii_bus) {
0220         err = -ENOMEM;
0221         goto err;
0222     }
0223 
0224     mii_bus->name = "bcma_mdio mii bus";
0225     sprintf(mii_bus->id, "%s-%d-%d", "bcma_mdio", core->bus->num,
0226         core->core_unit);
0227     mii_bus->priv = bgmac;
0228     mii_bus->read = bcma_mdio_mii_read;
0229     mii_bus->write = bcma_mdio_mii_write;
0230     mii_bus->reset = bcma_mdio_phy_reset;
0231     mii_bus->parent = &core->dev;
0232     mii_bus->phy_mask = ~(1 << bgmac->phyaddr);
0233 
0234     np = of_get_child_by_name(core->dev.of_node, "mdio");
0235 
0236     err = of_mdiobus_register(mii_bus, np);
0237     of_node_put(np);
0238     if (err) {
0239         dev_err(&core->dev, "Registration of mii bus failed\n");
0240         goto err_free_bus;
0241     }
0242 
0243     return mii_bus;
0244 
0245 err_free_bus:
0246     mdiobus_free(mii_bus);
0247 err:
0248     return ERR_PTR(err);
0249 }
0250 EXPORT_SYMBOL_GPL(bcma_mdio_mii_register);
0251 
0252 void bcma_mdio_mii_unregister(struct mii_bus *mii_bus)
0253 {
0254     if (!mii_bus)
0255         return;
0256 
0257     mdiobus_unregister(mii_bus);
0258     mdiobus_free(mii_bus);
0259 }
0260 EXPORT_SYMBOL_GPL(bcma_mdio_mii_unregister);
0261 
0262 MODULE_AUTHOR("Rafał Miłecki");
0263 MODULE_LICENSE("GPL");