fixed_phy.c 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230
  1. // SPDX-License-Identifier: GPL-2.0+
  2. /*
  3. * Fixed MDIO bus (MDIO bus emulation with fixed PHYs)
  4. *
  5. * Author: Vitaly Bordug <vbordug@ru.mvista.com>
  6. * Anton Vorontsov <avorontsov@ru.mvista.com>
  7. *
  8. * Copyright (c) 2006-2007 MontaVista Software, Inc.
  9. */
  10. #include <linux/kernel.h>
  11. #include <linux/module.h>
  12. #include <linux/mii.h>
  13. #include <linux/phy.h>
  14. #include <linux/phy_fixed.h>
  15. #include <linux/err.h>
  16. #include <linux/slab.h>
  17. #include <linux/of.h>
  18. #include <linux/netdevice.h>
  19. #include "swphy.h"
  20. /* The DSA loop driver may allocate 4 fixed PHY's, and 4 additional
  21. * fixed PHY's for a system should be sufficient.
  22. */
  23. #define NUM_FP 8
  24. struct fixed_phy {
  25. struct phy_device *phydev;
  26. struct fixed_phy_status status;
  27. int (*link_update)(struct net_device *, struct fixed_phy_status *);
  28. };
  29. static DECLARE_BITMAP(fixed_phy_ids, NUM_FP);
  30. static struct fixed_phy fmb_fixed_phys[NUM_FP];
  31. static struct mii_bus *fmb_mii_bus;
  32. static struct fixed_phy *fixed_phy_find(int addr)
  33. {
  34. return test_bit(addr, fixed_phy_ids) ? fmb_fixed_phys + addr : NULL;
  35. }
  36. int fixed_phy_change_carrier(struct net_device *dev, bool new_carrier)
  37. {
  38. struct phy_device *phydev = dev->phydev;
  39. struct fixed_phy *fp;
  40. if (!phydev || !phydev->mdio.bus)
  41. return -EINVAL;
  42. fp = fixed_phy_find(phydev->mdio.addr);
  43. if (!fp)
  44. return -EINVAL;
  45. fp->status.link = new_carrier;
  46. return 0;
  47. }
  48. EXPORT_SYMBOL_GPL(fixed_phy_change_carrier);
  49. static int fixed_mdio_read(struct mii_bus *bus, int phy_addr, int reg_num)
  50. {
  51. struct fixed_phy *fp;
  52. fp = fixed_phy_find(phy_addr);
  53. if (!fp)
  54. return 0xffff;
  55. if (fp->link_update)
  56. fp->link_update(fp->phydev->attached_dev, &fp->status);
  57. return swphy_read_reg(reg_num, &fp->status);
  58. }
  59. static int fixed_mdio_write(struct mii_bus *bus, int phy_addr, int reg_num,
  60. u16 val)
  61. {
  62. return 0;
  63. }
  64. /*
  65. * If something weird is required to be done with link/speed,
  66. * network driver is able to assign a function to implement this.
  67. * May be useful for PHY's that need to be software-driven.
  68. */
  69. int fixed_phy_set_link_update(struct phy_device *phydev,
  70. int (*link_update)(struct net_device *,
  71. struct fixed_phy_status *))
  72. {
  73. struct fixed_phy *fp;
  74. if (!phydev || !phydev->mdio.bus)
  75. return -EINVAL;
  76. fp = fixed_phy_find(phydev->mdio.addr);
  77. if (!fp)
  78. return -ENOENT;
  79. fp->link_update = link_update;
  80. fp->phydev = phydev;
  81. return 0;
  82. }
  83. EXPORT_SYMBOL_GPL(fixed_phy_set_link_update);
  84. static void fixed_phy_del(int phy_addr)
  85. {
  86. struct fixed_phy *fp;
  87. fp = fixed_phy_find(phy_addr);
  88. if (!fp)
  89. return;
  90. memset(fp, 0, sizeof(*fp));
  91. clear_bit(phy_addr, fixed_phy_ids);
  92. }
  93. static int fixed_phy_get_free_addr(void)
  94. {
  95. int addr;
  96. do {
  97. addr = find_first_zero_bit(fixed_phy_ids, NUM_FP);
  98. if (addr == NUM_FP)
  99. return -ENOSPC;
  100. } while (test_and_set_bit(addr, fixed_phy_ids));
  101. return addr;
  102. }
  103. struct phy_device *fixed_phy_register(const struct fixed_phy_status *status,
  104. struct device_node *np)
  105. {
  106. struct phy_device *phy;
  107. int phy_addr;
  108. int ret;
  109. ret = swphy_validate_state(status);
  110. if (ret < 0)
  111. return ERR_PTR(ret);
  112. if (!fmb_mii_bus || fmb_mii_bus->state != MDIOBUS_REGISTERED)
  113. return ERR_PTR(-EPROBE_DEFER);
  114. /* Get the next available PHY address, up to NUM_FP */
  115. phy_addr = fixed_phy_get_free_addr();
  116. if (phy_addr < 0)
  117. return ERR_PTR(phy_addr);
  118. fmb_fixed_phys[phy_addr].status = *status;
  119. fmb_fixed_phys[phy_addr].status.link = true;
  120. phy = get_phy_device(fmb_mii_bus, phy_addr, false);
  121. if (IS_ERR(phy)) {
  122. fixed_phy_del(phy_addr);
  123. return ERR_PTR(-EINVAL);
  124. }
  125. of_node_get(np);
  126. phy->mdio.dev.of_node = np;
  127. phy->is_pseudo_fixed_link = true;
  128. ret = phy_device_register(phy);
  129. if (ret) {
  130. phy_device_free(phy);
  131. of_node_put(np);
  132. fixed_phy_del(phy_addr);
  133. return ERR_PTR(ret);
  134. }
  135. return phy;
  136. }
  137. EXPORT_SYMBOL_GPL(fixed_phy_register);
  138. struct phy_device *fixed_phy_register_100fd(void)
  139. {
  140. static const struct fixed_phy_status status = {
  141. .speed = SPEED_100,
  142. .duplex = DUPLEX_FULL,
  143. };
  144. return fixed_phy_register(&status, NULL);
  145. }
  146. EXPORT_SYMBOL_GPL(fixed_phy_register_100fd);
  147. void fixed_phy_unregister(struct phy_device *phy)
  148. {
  149. phy_device_remove(phy);
  150. of_node_put(phy->mdio.dev.of_node);
  151. fixed_phy_del(phy->mdio.addr);
  152. phy_device_free(phy);
  153. }
  154. EXPORT_SYMBOL_GPL(fixed_phy_unregister);
  155. static int __init fixed_mdio_bus_init(void)
  156. {
  157. int ret;
  158. fmb_mii_bus = mdiobus_alloc();
  159. if (!fmb_mii_bus)
  160. return -ENOMEM;
  161. snprintf(fmb_mii_bus->id, MII_BUS_ID_SIZE, "fixed-0");
  162. fmb_mii_bus->name = "Fixed MDIO Bus";
  163. fmb_mii_bus->read = &fixed_mdio_read;
  164. fmb_mii_bus->write = &fixed_mdio_write;
  165. fmb_mii_bus->phy_mask = ~0;
  166. ret = mdiobus_register(fmb_mii_bus);
  167. if (ret)
  168. goto err_mdiobus_alloc;
  169. return 0;
  170. err_mdiobus_alloc:
  171. mdiobus_free(fmb_mii_bus);
  172. return ret;
  173. }
  174. module_init(fixed_mdio_bus_init);
  175. static void __exit fixed_mdio_bus_exit(void)
  176. {
  177. mdiobus_unregister(fmb_mii_bus);
  178. mdiobus_free(fmb_mii_bus);
  179. }
  180. module_exit(fixed_mdio_bus_exit);
  181. MODULE_DESCRIPTION("Fixed MDIO bus (MDIO bus emulation with fixed PHYs)");
  182. MODULE_AUTHOR("Vitaly Bordug");
  183. MODULE_LICENSE("GPL");