ihs_mdio.c 3.1 KB

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