cmd_mdio.c 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286
  1. /*
  2. * (C) Copyright 2011 Freescale Semiconductor, Inc
  3. * Andy Fleming
  4. *
  5. * See file CREDITS for list of people who contributed to this
  6. * project.
  7. *
  8. * This program is free software; you can redistribute it and/or
  9. * modify it under the terms of the GNU General Public License as
  10. * published by the Free Software Foundation; either version 2 of
  11. * the License, or (at your option) any later version.
  12. *
  13. * This program is distributed in the hope that it will be useful,
  14. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  15. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  16. * GNU General Public License for more details.
  17. *
  18. * You should have received a copy of the GNU General Public License
  19. * along with this program; if not, write to the Free Software
  20. * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
  21. * MA 02111-1307 USA
  22. */
  23. /*
  24. * MDIO Commands
  25. */
  26. #include <common.h>
  27. #include <command.h>
  28. #include <miiphy.h>
  29. #include <phy.h>
  30. static char last_op[2];
  31. static uint last_data;
  32. static uint last_addr_lo;
  33. static uint last_addr_hi;
  34. static uint last_devad_lo;
  35. static uint last_devad_hi;
  36. static uint last_reg_lo;
  37. static uint last_reg_hi;
  38. static int extract_range(char *input, int *plo, int *phi)
  39. {
  40. char *end;
  41. *plo = simple_strtol(input, &end, 0);
  42. if (end == input)
  43. return -1;
  44. if ((*end == '-') && *(++end))
  45. *phi = simple_strtol(end, NULL, 0);
  46. else if (*end == '\0')
  47. *phi = *plo;
  48. else
  49. return -1;
  50. return 0;
  51. }
  52. int mdio_write_ranges(struct mii_dev *bus, int addrlo,
  53. int addrhi, int devadlo, int devadhi,
  54. int reglo, int reghi, unsigned short data)
  55. {
  56. int addr, devad, reg;
  57. int err = 0;
  58. for (addr = addrlo; addr <= addrhi; addr++) {
  59. for (devad = devadlo; devad <= devadhi; devad++) {
  60. for (reg = reglo; reg <= reghi; reg++) {
  61. err = bus->write(bus, addr, devad, reg, data);
  62. if (err)
  63. goto err_out;
  64. }
  65. }
  66. }
  67. err_out:
  68. return err;
  69. }
  70. int mdio_read_ranges(struct mii_dev *bus, int addrlo,
  71. int addrhi, int devadlo, int devadhi,
  72. int reglo, int reghi)
  73. {
  74. int addr, devad, reg;
  75. printf("Reading from bus %s\n", bus->name);
  76. for (addr = addrlo; addr <= addrhi; addr++) {
  77. printf("PHY at address %d:\n", addr);
  78. for (devad = devadlo; devad <= devadhi; devad++) {
  79. for (reg = reglo; reg <= reghi; reg++) {
  80. int val;
  81. val = bus->read(bus, addr, devad, reg);
  82. if (val < 0) {
  83. printf("Error\n");
  84. return val;
  85. }
  86. if (devad >= 0)
  87. printf("%d.", devad);
  88. printf("%d - 0x%x\n", reg, val & 0xffff);
  89. }
  90. }
  91. }
  92. return 0;
  93. }
  94. /* The register will be in the form [a[-b].]x[-y] */
  95. int extract_reg_range(char *input, int *devadlo, int *devadhi,
  96. int *reglo, int *reghi)
  97. {
  98. char *regstr;
  99. /* use strrchr to find the last string after a '.' */
  100. regstr = strrchr(input, '.');
  101. /* If it exists, extract the devad(s) */
  102. if (regstr) {
  103. char devadstr[32];
  104. strncpy(devadstr, input, regstr - input);
  105. devadstr[regstr - input] = '\0';
  106. if (extract_range(devadstr, devadlo, devadhi))
  107. return -1;
  108. regstr++;
  109. } else {
  110. /* Otherwise, we have no devad, and we just got regs */
  111. *devadlo = *devadhi = MDIO_DEVAD_NONE;
  112. regstr = input;
  113. }
  114. return extract_range(regstr, reglo, reghi);
  115. }
  116. int extract_phy_range(char *const argv[], int argc, struct mii_dev **bus,
  117. int *addrlo, int *addrhi)
  118. {
  119. struct phy_device *phydev;
  120. if ((argc < 1) || (argc > 2))
  121. return -1;
  122. /* If there are two arguments, it's busname addr */
  123. if (argc == 2) {
  124. *bus = miiphy_get_dev_by_name(argv[0]);
  125. if (!*bus)
  126. return -1;
  127. return extract_range(argv[1], addrlo, addrhi);
  128. }
  129. /* It must be one argument, here */
  130. /*
  131. * This argument can be one of two things:
  132. * 1) Ethernet device name
  133. * 2) Just an address (use the previously-used bus)
  134. *
  135. * We check all buses for a PHY which is connected to an ethernet
  136. * device by the given name. If none are found, we call
  137. * extract_range() on the string, and see if it's an address range.
  138. */
  139. phydev = mdio_phydev_for_ethname(argv[0]);
  140. if (phydev) {
  141. *addrlo = *addrhi = phydev->addr;
  142. *bus = phydev->bus;
  143. return 0;
  144. }
  145. /* It's an address or nothing useful */
  146. return extract_range(argv[0], addrlo, addrhi);
  147. }
  148. /* ---------------------------------------------------------------- */
  149. static int do_mdio(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
  150. {
  151. char op[2];
  152. int addrlo, addrhi, reglo, reghi, devadlo, devadhi;
  153. unsigned short data;
  154. int pos = argc - 1;
  155. struct mii_dev *bus;
  156. if (argc < 2)
  157. return CMD_RET_USAGE;
  158. /*
  159. * We use the last specified parameters, unless new ones are
  160. * entered.
  161. */
  162. op[0] = argv[1][0];
  163. addrlo = last_addr_lo;
  164. addrhi = last_addr_hi;
  165. devadlo = last_devad_lo;
  166. devadhi = last_devad_hi;
  167. reglo = last_reg_lo;
  168. reghi = last_reg_hi;
  169. data = last_data;
  170. bus = mdio_get_current_dev();
  171. if (flag & CMD_FLAG_REPEAT)
  172. op[0] = last_op[0];
  173. switch (op[0]) {
  174. case 'w':
  175. if (pos > 1)
  176. data = simple_strtoul(argv[pos--], NULL, 16);
  177. case 'r':
  178. if (pos > 1)
  179. if (extract_reg_range(argv[pos--], &devadlo, &devadhi,
  180. &reglo, &reghi))
  181. return -1;
  182. default:
  183. if (pos > 1)
  184. if (extract_phy_range(&(argv[2]), pos - 1, &bus,
  185. &addrlo, &addrhi))
  186. return -1;
  187. break;
  188. }
  189. if (op[0] == 'l') {
  190. mdio_list_devices();
  191. return 0;
  192. }
  193. /* Save the chosen bus */
  194. miiphy_set_current_dev(bus->name);
  195. switch (op[0]) {
  196. case 'w':
  197. mdio_write_ranges(bus, addrlo, addrhi, devadlo, devadhi,
  198. reglo, reghi, data);
  199. break;
  200. case 'r':
  201. mdio_read_ranges(bus, addrlo, addrhi, devadlo, devadhi,
  202. reglo, reghi);
  203. break;
  204. }
  205. /*
  206. * Save the parameters for repeats.
  207. */
  208. last_op[0] = op[0];
  209. last_addr_lo = addrlo;
  210. last_addr_hi = addrhi;
  211. last_devad_lo = devadlo;
  212. last_devad_hi = devadhi;
  213. last_reg_lo = reglo;
  214. last_reg_hi = reghi;
  215. last_data = data;
  216. return 0;
  217. }
  218. /***************************************************/
  219. U_BOOT_CMD(
  220. mdio, 6, 1, do_mdio,
  221. "MDIO utility commands",
  222. "list - List MDIO buses\n"
  223. "mdio read <phydev> [<devad>.]<reg> - "
  224. "read PHY's register at <devad>.<reg>\n"
  225. "mdio write <phydev> [<devad>.]<reg> <data> - "
  226. "write PHY's register at <devad>.<reg>\n"
  227. "<phydev> may be:\n"
  228. " <busname> <addr>\n"
  229. " <addr>\n"
  230. " <eth name>\n"
  231. "<addr> <devad>, and <reg> may be ranges, e.g. 1-5.4-0x1f.\n"
  232. );