bgmac-bcma-mdio.c 7.3 KB

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