fsl_mdio.c 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255
  1. // SPDX-License-Identifier: GPL-2.0+
  2. /*
  3. * Copyright 2009-2010, 2013 Freescale Semiconductor, Inc.
  4. * Jun-jie Zhang <b18070@freescale.com>
  5. * Mingkai Hu <Mingkai.hu@freescale.com>
  6. */
  7. #include <common.h>
  8. #include <miiphy.h>
  9. #include <phy.h>
  10. #include <fsl_mdio.h>
  11. #include <asm/io.h>
  12. #include <linux/errno.h>
  13. #include <tsec.h>
  14. #ifdef CONFIG_DM_MDIO
  15. struct tsec_mdio_priv {
  16. struct tsec_mii_mng __iomem *regs;
  17. };
  18. #endif
  19. void tsec_local_mdio_write(struct tsec_mii_mng __iomem *phyregs, int port_addr,
  20. int dev_addr, int regnum, int value)
  21. {
  22. int timeout = 1000000;
  23. out_be32(&phyregs->miimadd, (port_addr << 8) | (regnum & 0x1f));
  24. out_be32(&phyregs->miimcon, value);
  25. /* Memory barrier */
  26. mb();
  27. while ((in_be32(&phyregs->miimind) & MIIMIND_BUSY) && timeout--)
  28. ;
  29. }
  30. int tsec_local_mdio_read(struct tsec_mii_mng __iomem *phyregs, int port_addr,
  31. int dev_addr, int regnum)
  32. {
  33. int value;
  34. int timeout = 1000000;
  35. /* Put the address of the phy, and the register number into MIIMADD */
  36. out_be32(&phyregs->miimadd, (port_addr << 8) | (regnum & 0x1f));
  37. /* Clear the command register, and wait */
  38. out_be32(&phyregs->miimcom, 0);
  39. /* Memory barrier */
  40. mb();
  41. /* Initiate a read command, and wait */
  42. out_be32(&phyregs->miimcom, MIIMCOM_READ_CYCLE);
  43. /* Memory barrier */
  44. mb();
  45. /* Wait for the the indication that the read is done */
  46. while ((in_be32(&phyregs->miimind) & (MIIMIND_NOTVALID | MIIMIND_BUSY))
  47. && timeout--)
  48. ;
  49. /* Grab the value read from the PHY */
  50. value = in_be32(&phyregs->miimstat);
  51. return value;
  52. }
  53. #if defined(CONFIG_PHYLIB)
  54. static int fsl_pq_mdio_reset(struct mii_dev *bus)
  55. {
  56. struct tsec_mii_mng __iomem *regs;
  57. #ifndef CONFIG_DM_MDIO
  58. regs = (struct tsec_mii_mng __iomem *)bus->priv;
  59. #else
  60. struct tsec_mdio_priv *priv;
  61. if (!bus->priv)
  62. return -EINVAL;
  63. priv = dev_get_priv(bus->priv);
  64. regs = priv->regs;
  65. #endif
  66. /* Reset MII (due to new addresses) */
  67. out_be32(&regs->miimcfg, MIIMCFG_RESET_MGMT);
  68. out_be32(&regs->miimcfg, MIIMCFG_INIT_VALUE);
  69. while (in_be32(&regs->miimind) & MIIMIND_BUSY)
  70. ;
  71. return 0;
  72. }
  73. #endif
  74. int tsec_phy_read(struct mii_dev *bus, int addr, int dev_addr, int regnum)
  75. {
  76. struct tsec_mii_mng __iomem *phyregs;
  77. #ifndef CONFIG_DM_MDIO
  78. phyregs = (struct tsec_mii_mng __iomem *)bus->priv;
  79. #else
  80. struct tsec_mdio_priv *priv;
  81. if (!bus->priv)
  82. return -EINVAL;
  83. priv = dev_get_priv(bus->priv);
  84. phyregs = priv->regs;
  85. #endif
  86. return tsec_local_mdio_read(phyregs, addr, dev_addr, regnum);
  87. }
  88. int tsec_phy_write(struct mii_dev *bus, int addr, int dev_addr, int regnum,
  89. u16 value)
  90. {
  91. struct tsec_mii_mng __iomem *phyregs;
  92. #ifndef CONFIG_DM_MDIO
  93. phyregs = (struct tsec_mii_mng __iomem *)bus->priv;
  94. #else
  95. struct tsec_mdio_priv *priv;
  96. if (!bus->priv)
  97. return -EINVAL;
  98. priv = dev_get_priv(bus->priv);
  99. phyregs = priv->regs;
  100. #endif
  101. tsec_local_mdio_write(phyregs, addr, dev_addr, regnum, value);
  102. return 0;
  103. }
  104. #ifndef CONFIG_DM_MDIO
  105. int fsl_pq_mdio_init(struct bd_info *bis, struct fsl_pq_mdio_info *info)
  106. {
  107. struct mii_dev *bus = mdio_alloc();
  108. if (!bus) {
  109. printf("Failed to allocate FSL MDIO bus\n");
  110. return -1;
  111. }
  112. bus->read = tsec_phy_read;
  113. bus->write = tsec_phy_write;
  114. bus->reset = fsl_pq_mdio_reset;
  115. strcpy(bus->name, info->name);
  116. bus->priv = (void *)info->regs;
  117. return mdio_register(bus);
  118. }
  119. #else /* CONFIG_DM_MDIO */
  120. #if defined(CONFIG_PHYLIB)
  121. static int tsec_mdio_read(struct udevice *dev, int addr, int devad, int reg)
  122. {
  123. struct mdio_perdev_priv *pdata = (dev) ? dev_get_uclass_priv(dev) :
  124. NULL;
  125. if (pdata && pdata->mii_bus)
  126. return tsec_phy_read(pdata->mii_bus, addr, devad, reg);
  127. return -1;
  128. }
  129. static int tsec_mdio_write(struct udevice *dev, int addr, int devad, int reg,
  130. u16 val)
  131. {
  132. struct mdio_perdev_priv *pdata = (dev) ? dev_get_uclass_priv(dev) :
  133. NULL;
  134. if (pdata && pdata->mii_bus)
  135. return tsec_phy_write(pdata->mii_bus, addr, devad, reg, val);
  136. return -1;
  137. }
  138. static int tsec_mdio_reset(struct udevice *dev)
  139. {
  140. struct mdio_perdev_priv *pdata = (dev) ? dev_get_uclass_priv(dev) :
  141. NULL;
  142. if (pdata && pdata->mii_bus)
  143. return fsl_pq_mdio_reset(pdata->mii_bus);
  144. return -1;
  145. }
  146. static const struct mdio_ops tsec_mdio_ops = {
  147. .read = tsec_mdio_read,
  148. .write = tsec_mdio_write,
  149. .reset = tsec_mdio_reset,
  150. };
  151. static struct fsl_pq_mdio_data etsec2_data = {
  152. .mdio_regs_off = TSEC_MDIO_REGS_OFFSET,
  153. };
  154. static struct fsl_pq_mdio_data gianfar_data = {
  155. .mdio_regs_off = 0x0,
  156. };
  157. static struct fsl_pq_mdio_data fman_data = {
  158. .mdio_regs_off = 0x0,
  159. };
  160. static const struct udevice_id tsec_mdio_ids[] = {
  161. { .compatible = "fsl,gianfar-tbi", .data = (ulong)&gianfar_data },
  162. { .compatible = "fsl,gianfar-mdio", .data = (ulong)&gianfar_data },
  163. { .compatible = "fsl,etsec2-tbi", .data = (ulong)&etsec2_data },
  164. { .compatible = "fsl,etsec2-mdio", .data = (ulong)&etsec2_data },
  165. { .compatible = "fsl,fman-mdio", .data = (ulong)&fman_data },
  166. {}
  167. };
  168. static int tsec_mdio_probe(struct udevice *dev)
  169. {
  170. struct fsl_pq_mdio_data *data;
  171. struct tsec_mdio_priv *priv = (dev) ? dev_get_priv(dev) : NULL;
  172. struct mdio_perdev_priv *pdata = (dev) ? dev_get_uclass_priv(dev) :
  173. NULL;
  174. if (!dev) {
  175. printf("%s dev = NULL\n", __func__);
  176. return -1;
  177. }
  178. if (!priv) {
  179. printf("dev_get_priv(dev %p) = NULL\n", dev);
  180. return -1;
  181. }
  182. data = (struct fsl_pq_mdio_data *)dev_get_driver_data(dev);
  183. priv->regs = dev_remap_addr(dev) + data->mdio_regs_off;
  184. debug("%s priv %p @ regs %p, pdata %p\n", __func__,
  185. priv, priv->regs, pdata);
  186. return 0;
  187. }
  188. static int tsec_mdio_remove(struct udevice *dev)
  189. {
  190. return 0;
  191. }
  192. U_BOOT_DRIVER(tsec_mdio) = {
  193. .name = "tsec_mdio",
  194. .id = UCLASS_MDIO,
  195. .of_match = tsec_mdio_ids,
  196. .probe = tsec_mdio_probe,
  197. .remove = tsec_mdio_remove,
  198. .ops = &tsec_mdio_ops,
  199. .priv_auto = sizeof(struct tsec_mdio_priv),
  200. .plat_auto = sizeof(struct mdio_perdev_priv),
  201. };
  202. #endif /* CONFIG_PHYLIB */
  203. #endif /* CONFIG_DM_MDIO */