ihs_mdio.c 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164
  1. // SPDX-License-Identifier: GPL-2.0+
  2. /*
  3. * (C) Copyright 2014
  4. * Dirk Eibach, Guntermann & Drunck GmbH, dirk.eibach@gdsys.cc
  5. */
  6. #include <common.h>
  7. #include <linux/delay.h>
  8. #include <miiphy.h>
  9. #ifdef CONFIG_GDSYS_LEGACY_DRIVERS
  10. #include <gdsys_fpga.h>
  11. #else
  12. #include <fdtdec.h>
  13. #include <dm.h>
  14. #include <regmap.h>
  15. #endif
  16. #include "ihs_mdio.h"
  17. #ifndef CONFIG_GDSYS_LEGACY_DRIVERS
  18. enum {
  19. REG_MDIO_CONTROL = 0x0,
  20. REG_MDIO_ADDR_DATA = 0x2,
  21. REG_MDIO_RX_DATA = 0x4,
  22. };
  23. static inline u16 read_reg(struct udevice *fpga, uint base, uint addr)
  24. {
  25. struct regmap *map;
  26. u8 *ptr;
  27. regmap_init_mem(dev_ofnode(fpga), &map);
  28. ptr = regmap_get_range(map, 0);
  29. return in_le16((u16 *)(ptr + base + addr));
  30. }
  31. static inline void write_reg(struct udevice *fpga, uint base, uint addr,
  32. u16 val)
  33. {
  34. struct regmap *map;
  35. u8 *ptr;
  36. regmap_init_mem(dev_ofnode(fpga), &map);
  37. ptr = regmap_get_range(map, 0);
  38. out_le16((u16 *)(ptr + base + addr), val);
  39. }
  40. #endif
  41. static inline u16 read_control(struct ihs_mdio_info *info)
  42. {
  43. u16 val;
  44. #ifdef CONFIG_GDSYS_LEGACY_DRIVERS
  45. FPGA_GET_REG(info->fpga, mdio.control, &val);
  46. #else
  47. val = read_reg(info->fpga, info->base, REG_MDIO_CONTROL);
  48. #endif
  49. return val;
  50. }
  51. static inline void write_control(struct ihs_mdio_info *info, u16 val)
  52. {
  53. #ifdef CONFIG_GDSYS_LEGACY_DRIVERS
  54. FPGA_SET_REG(info->fpga, mdio.control, val);
  55. #else
  56. write_reg(info->fpga, info->base, REG_MDIO_CONTROL, val);
  57. #endif
  58. }
  59. static inline void write_addr_data(struct ihs_mdio_info *info, u16 val)
  60. {
  61. #ifdef CONFIG_GDSYS_LEGACY_DRIVERS
  62. FPGA_SET_REG(info->fpga, mdio.address_data, val);
  63. #else
  64. write_reg(info->fpga, info->base, REG_MDIO_ADDR_DATA, val);
  65. #endif
  66. }
  67. static inline u16 read_rx_data(struct ihs_mdio_info *info)
  68. {
  69. u16 val;
  70. #ifdef CONFIG_GDSYS_LEGACY_DRIVERS
  71. FPGA_GET_REG(info->fpga, mdio.rx_data, &val);
  72. #else
  73. val = read_reg(info->fpga, info->base, REG_MDIO_RX_DATA);
  74. #endif
  75. return val;
  76. }
  77. static int ihs_mdio_idle(struct mii_dev *bus)
  78. {
  79. struct ihs_mdio_info *info = bus->priv;
  80. u16 val;
  81. unsigned int ctr = 0;
  82. do {
  83. val = read_control(info);
  84. udelay(100);
  85. if (ctr++ > 10)
  86. return -1;
  87. } while (!(val & (1 << 12)));
  88. return 0;
  89. }
  90. static int ihs_mdio_reset(struct mii_dev *bus)
  91. {
  92. ihs_mdio_idle(bus);
  93. return 0;
  94. }
  95. static int ihs_mdio_read(struct mii_dev *bus, int addr, int dev_addr,
  96. int regnum)
  97. {
  98. struct ihs_mdio_info *info = bus->priv;
  99. u16 val;
  100. ihs_mdio_idle(bus);
  101. write_control(info,
  102. ((addr & 0x1f) << 5) | (regnum & 0x1f) | (2 << 10));
  103. /* wait for rx data available */
  104. udelay(100);
  105. val = read_rx_data(info);
  106. return val;
  107. }
  108. static int ihs_mdio_write(struct mii_dev *bus, int addr, int dev_addr,
  109. int regnum, u16 value)
  110. {
  111. struct ihs_mdio_info *info = bus->priv;
  112. ihs_mdio_idle(bus);
  113. write_addr_data(info, value);
  114. write_control(info, ((addr & 0x1f) << 5) | (regnum & 0x1f) | (1 << 10));
  115. return 0;
  116. }
  117. int ihs_mdio_init(struct ihs_mdio_info *info)
  118. {
  119. struct mii_dev *bus = mdio_alloc();
  120. if (!bus) {
  121. printf("Failed to allocate FSL MDIO bus\n");
  122. return -1;
  123. }
  124. bus->read = ihs_mdio_read;
  125. bus->write = ihs_mdio_write;
  126. bus->reset = ihs_mdio_reset;
  127. strcpy(bus->name, info->name);
  128. bus->priv = info;
  129. return mdio_register(bus);
  130. }