bgmac-bcma-mdio.c 7.3 KB

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