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 "bgmac.h" 14 15 struct bcma_mdio { 16 struct bcma_device *core; 17 u8 phyaddr; 18 }; 19 20 static bool bcma_mdio_wait_value(struct bcma_device *core, u16 reg, u32 mask, 21 u32 value, int timeout) 22 { 23 u32 val; 24 int i; 25 26 for (i = 0; i < timeout / 10; i++) { 27 val = bcma_read32(core, reg); 28 if ((val & mask) == value) 29 return true; 30 udelay(10); 31 } 32 dev_err(&core->dev, "Timeout waiting for reg 0x%X\n", reg); 33 return false; 34 } 35 36 /************************************************** 37 * PHY ops 38 **************************************************/ 39 40 static u16 bcma_mdio_phy_read(struct bcma_mdio *bcma_mdio, u8 phyaddr, u8 reg) 41 { 42 struct bcma_device *core; 43 u16 phy_access_addr; 44 u16 phy_ctl_addr; 45 u32 tmp; 46 47 BUILD_BUG_ON(BGMAC_PA_DATA_MASK != BCMA_GMAC_CMN_PA_DATA_MASK); 48 BUILD_BUG_ON(BGMAC_PA_ADDR_MASK != BCMA_GMAC_CMN_PA_ADDR_MASK); 49 BUILD_BUG_ON(BGMAC_PA_ADDR_SHIFT != BCMA_GMAC_CMN_PA_ADDR_SHIFT); 50 BUILD_BUG_ON(BGMAC_PA_REG_MASK != BCMA_GMAC_CMN_PA_REG_MASK); 51 BUILD_BUG_ON(BGMAC_PA_REG_SHIFT != BCMA_GMAC_CMN_PA_REG_SHIFT); 52 BUILD_BUG_ON(BGMAC_PA_WRITE != BCMA_GMAC_CMN_PA_WRITE); 53 BUILD_BUG_ON(BGMAC_PA_START != BCMA_GMAC_CMN_PA_START); 54 BUILD_BUG_ON(BGMAC_PC_EPA_MASK != BCMA_GMAC_CMN_PC_EPA_MASK); 55 BUILD_BUG_ON(BGMAC_PC_MCT_MASK != BCMA_GMAC_CMN_PC_MCT_MASK); 56 BUILD_BUG_ON(BGMAC_PC_MCT_SHIFT != BCMA_GMAC_CMN_PC_MCT_SHIFT); 57 BUILD_BUG_ON(BGMAC_PC_MTE != BCMA_GMAC_CMN_PC_MTE); 58 59 if (bcma_mdio->core->id.id == BCMA_CORE_4706_MAC_GBIT) { 60 core = bcma_mdio->core->bus->drv_gmac_cmn.core; 61 phy_access_addr = BCMA_GMAC_CMN_PHY_ACCESS; 62 phy_ctl_addr = BCMA_GMAC_CMN_PHY_CTL; 63 } else { 64 core = bcma_mdio->core; 65 phy_access_addr = BGMAC_PHY_ACCESS; 66 phy_ctl_addr = BGMAC_PHY_CNTL; 67 } 68 69 tmp = bcma_read32(core, phy_ctl_addr); 70 tmp &= ~BGMAC_PC_EPA_MASK; 71 tmp |= phyaddr; 72 bcma_write32(core, phy_ctl_addr, tmp); 73 74 tmp = BGMAC_PA_START; 75 tmp |= phyaddr << BGMAC_PA_ADDR_SHIFT; 76 tmp |= reg << BGMAC_PA_REG_SHIFT; 77 bcma_write32(core, phy_access_addr, tmp); 78 79 if (!bcma_mdio_wait_value(core, phy_access_addr, BGMAC_PA_START, 0, 80 1000)) { 81 dev_err(&core->dev, "Reading PHY %d register 0x%X failed\n", 82 phyaddr, reg); 83 return 0xffff; 84 } 85 86 return bcma_read32(core, phy_access_addr) & BGMAC_PA_DATA_MASK; 87 } 88 89 /* http://bcm-v4.sipsolutions.net/mac-gbit/gmac/chipphywr */ 90 static int bcma_mdio_phy_write(struct bcma_mdio *bcma_mdio, u8 phyaddr, u8 reg, 91 u16 value) 92 { 93 struct bcma_device *core; 94 u16 phy_access_addr; 95 u16 phy_ctl_addr; 96 u32 tmp; 97 98 if (bcma_mdio->core->id.id == BCMA_CORE_4706_MAC_GBIT) { 99 core = bcma_mdio->core->bus->drv_gmac_cmn.core; 100 phy_access_addr = BCMA_GMAC_CMN_PHY_ACCESS; 101 phy_ctl_addr = BCMA_GMAC_CMN_PHY_CTL; 102 } else { 103 core = bcma_mdio->core; 104 phy_access_addr = BGMAC_PHY_ACCESS; 105 phy_ctl_addr = BGMAC_PHY_CNTL; 106 } 107 108 tmp = bcma_read32(core, phy_ctl_addr); 109 tmp &= ~BGMAC_PC_EPA_MASK; 110 tmp |= phyaddr; 111 bcma_write32(core, phy_ctl_addr, tmp); 112 113 bcma_write32(bcma_mdio->core, BGMAC_INT_STATUS, BGMAC_IS_MDIO); 114 if (bcma_read32(bcma_mdio->core, BGMAC_INT_STATUS) & BGMAC_IS_MDIO) 115 dev_warn(&core->dev, "Error setting MDIO int\n"); 116 117 tmp = BGMAC_PA_START; 118 tmp |= BGMAC_PA_WRITE; 119 tmp |= phyaddr << BGMAC_PA_ADDR_SHIFT; 120 tmp |= reg << BGMAC_PA_REG_SHIFT; 121 tmp |= value; 122 bcma_write32(core, phy_access_addr, tmp); 123 124 if (!bcma_mdio_wait_value(core, phy_access_addr, BGMAC_PA_START, 0, 125 1000)) { 126 dev_err(&core->dev, "Writing to PHY %d register 0x%X failed\n", 127 phyaddr, reg); 128 return -ETIMEDOUT; 129 } 130 131 return 0; 132 } 133 134 /* http://bcm-v4.sipsolutions.net/mac-gbit/gmac/chipphyinit */ 135 static void bcma_mdio_phy_init(struct bcma_mdio *bcma_mdio) 136 { 137 struct bcma_chipinfo *ci = &bcma_mdio->core->bus->chipinfo; 138 u8 i; 139 140 if (ci->id == BCMA_CHIP_ID_BCM5356) { 141 for (i = 0; i < 5; i++) { 142 bcma_mdio_phy_write(bcma_mdio, i, 0x1f, 0x008b); 143 bcma_mdio_phy_write(bcma_mdio, i, 0x15, 0x0100); 144 bcma_mdio_phy_write(bcma_mdio, i, 0x1f, 0x000f); 145 bcma_mdio_phy_write(bcma_mdio, i, 0x12, 0x2aaa); 146 bcma_mdio_phy_write(bcma_mdio, i, 0x1f, 0x000b); 147 } 148 } 149 if ((ci->id == BCMA_CHIP_ID_BCM5357 && ci->pkg != 10) || 150 (ci->id == BCMA_CHIP_ID_BCM4749 && ci->pkg != 10) || 151 (ci->id == BCMA_CHIP_ID_BCM53572 && ci->pkg != 9)) { 152 struct bcma_drv_cc *cc = &bcma_mdio->core->bus->drv_cc; 153 154 bcma_chipco_chipctl_maskset(cc, 2, ~0xc0000000, 0); 155 bcma_chipco_chipctl_maskset(cc, 4, ~0x80000000, 0); 156 for (i = 0; i < 5; i++) { 157 bcma_mdio_phy_write(bcma_mdio, i, 0x1f, 0x000f); 158 bcma_mdio_phy_write(bcma_mdio, i, 0x16, 0x5284); 159 bcma_mdio_phy_write(bcma_mdio, i, 0x1f, 0x000b); 160 bcma_mdio_phy_write(bcma_mdio, i, 0x17, 0x0010); 161 bcma_mdio_phy_write(bcma_mdio, i, 0x1f, 0x000f); 162 bcma_mdio_phy_write(bcma_mdio, i, 0x16, 0x5296); 163 bcma_mdio_phy_write(bcma_mdio, i, 0x17, 0x1073); 164 bcma_mdio_phy_write(bcma_mdio, i, 0x17, 0x9073); 165 bcma_mdio_phy_write(bcma_mdio, i, 0x16, 0x52b6); 166 bcma_mdio_phy_write(bcma_mdio, i, 0x17, 0x9273); 167 bcma_mdio_phy_write(bcma_mdio, i, 0x1f, 0x000b); 168 } 169 } 170 } 171 172 /* http://bcm-v4.sipsolutions.net/mac-gbit/gmac/chipphyreset */ 173 static int bcma_mdio_phy_reset(struct mii_bus *bus) 174 { 175 struct bcma_mdio *bcma_mdio = bus->priv; 176 u8 phyaddr = bcma_mdio->phyaddr; 177 178 if (bcma_mdio->phyaddr == BGMAC_PHY_NOREGS) 179 return 0; 180 181 bcma_mdio_phy_write(bcma_mdio, phyaddr, MII_BMCR, BMCR_RESET); 182 udelay(100); 183 if (bcma_mdio_phy_read(bcma_mdio, phyaddr, MII_BMCR) & BMCR_RESET) 184 dev_err(&bcma_mdio->core->dev, "PHY reset failed\n"); 185 bcma_mdio_phy_init(bcma_mdio); 186 187 return 0; 188 } 189 190 /************************************************** 191 * MII 192 **************************************************/ 193 194 static int bcma_mdio_mii_read(struct mii_bus *bus, int mii_id, int regnum) 195 { 196 return bcma_mdio_phy_read(bus->priv, mii_id, regnum); 197 } 198 199 static int bcma_mdio_mii_write(struct mii_bus *bus, int mii_id, int regnum, 200 u16 value) 201 { 202 return bcma_mdio_phy_write(bus->priv, mii_id, regnum, value); 203 } 204 205 struct mii_bus *bcma_mdio_mii_register(struct bcma_device *core, u8 phyaddr) 206 { 207 struct bcma_mdio *bcma_mdio; 208 struct mii_bus *mii_bus; 209 int err; 210 211 bcma_mdio = kzalloc(sizeof(*bcma_mdio), GFP_KERNEL); 212 if (!bcma_mdio) 213 return ERR_PTR(-ENOMEM); 214 215 mii_bus = mdiobus_alloc(); 216 if (!mii_bus) { 217 err = -ENOMEM; 218 goto err; 219 } 220 221 mii_bus->name = "bcma_mdio mii bus"; 222 sprintf(mii_bus->id, "%s-%d-%d", "bcma_mdio", core->bus->num, 223 core->core_unit); 224 mii_bus->priv = bcma_mdio; 225 mii_bus->read = bcma_mdio_mii_read; 226 mii_bus->write = bcma_mdio_mii_write; 227 mii_bus->reset = bcma_mdio_phy_reset; 228 mii_bus->parent = &core->dev; 229 mii_bus->phy_mask = ~(1 << phyaddr); 230 231 bcma_mdio->core = core; 232 bcma_mdio->phyaddr = phyaddr; 233 234 err = mdiobus_register(mii_bus); 235 if (err) { 236 dev_err(&core->dev, "Registration of mii bus failed\n"); 237 goto err_free_bus; 238 } 239 240 return mii_bus; 241 242 err_free_bus: 243 mdiobus_free(mii_bus); 244 err: 245 kfree(bcma_mdio); 246 return ERR_PTR(err); 247 } 248 EXPORT_SYMBOL_GPL(bcma_mdio_mii_register); 249 250 void bcma_mdio_mii_unregister(struct mii_bus *mii_bus) 251 { 252 struct bcma_mdio *bcma_mdio; 253 254 if (!mii_bus) 255 return; 256 257 bcma_mdio = mii_bus->priv; 258 259 mdiobus_unregister(mii_bus); 260 mdiobus_free(mii_bus); 261 kfree(bcma_mdio); 262 } 263 EXPORT_SYMBOL_GPL(bcma_mdio_mii_unregister); 264 265 MODULE_AUTHOR("Rafał Miłecki"); 266 MODULE_LICENSE("GPL"); 267