bgmac-bcma-mdio.c 7.2 KB

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