mdio.c 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334
  1. // SPDX-License-Identifier: GPL-2.0+
  2. /*
  3. * (C) Copyright 2011 Freescale Semiconductor, Inc
  4. * Andy Fleming
  5. */
  6. /*
  7. * MDIO Commands
  8. */
  9. #include <common.h>
  10. #include <command.h>
  11. #include <dm.h>
  12. #include <miiphy.h>
  13. #include <phy.h>
  14. static char last_op[2];
  15. static uint last_data;
  16. static uint last_addr_lo;
  17. static uint last_addr_hi;
  18. static uint last_devad_lo;
  19. static uint last_devad_hi;
  20. static uint last_reg_lo;
  21. static uint last_reg_hi;
  22. static int extract_range(char *input, int *plo, int *phi)
  23. {
  24. char *end;
  25. *plo = simple_strtol(input, &end, 16);
  26. if (end == input)
  27. return -1;
  28. if ((*end == '-') && *(++end))
  29. *phi = simple_strtol(end, NULL, 16);
  30. else if (*end == '\0')
  31. *phi = *plo;
  32. else
  33. return -1;
  34. return 0;
  35. }
  36. static int mdio_write_ranges(struct mii_dev *bus,
  37. int addrlo,
  38. int addrhi, int devadlo, int devadhi,
  39. int reglo, int reghi, unsigned short data,
  40. int extended)
  41. {
  42. struct phy_device *phydev;
  43. int addr, devad, reg;
  44. int err = 0;
  45. for (addr = addrlo; addr <= addrhi; addr++) {
  46. phydev = bus->phymap[addr];
  47. for (devad = devadlo; devad <= devadhi; devad++) {
  48. for (reg = reglo; reg <= reghi; reg++) {
  49. if (!phydev)
  50. err = bus->write(bus, addr, devad,
  51. reg, data);
  52. else if (!extended)
  53. err = phy_write_mmd(phydev, devad,
  54. reg, data);
  55. else
  56. err = phydev->drv->writeext(phydev,
  57. addr, devad, reg, data);
  58. if (err)
  59. goto err_out;
  60. }
  61. }
  62. }
  63. err_out:
  64. return err;
  65. }
  66. static int mdio_read_ranges(struct mii_dev *bus,
  67. int addrlo,
  68. int addrhi, int devadlo, int devadhi,
  69. int reglo, int reghi, int extended)
  70. {
  71. int addr, devad, reg;
  72. struct phy_device *phydev;
  73. printf("Reading from bus %s\n", bus->name);
  74. for (addr = addrlo; addr <= addrhi; addr++) {
  75. phydev = bus->phymap[addr];
  76. printf("PHY at address %x:\n", addr);
  77. for (devad = devadlo; devad <= devadhi; devad++) {
  78. for (reg = reglo; reg <= reghi; reg++) {
  79. int val;
  80. if (!phydev)
  81. val = bus->read(bus, addr, devad, reg);
  82. else if (!extended)
  83. val = phy_read_mmd(phydev, devad, reg);
  84. else
  85. val = phydev->drv->readext(phydev, addr,
  86. devad, reg);
  87. if (val < 0) {
  88. printf("Error\n");
  89. return val;
  90. }
  91. if (devad >= 0)
  92. printf("%d.", devad);
  93. printf("%d - 0x%x\n", reg, val & 0xffff);
  94. }
  95. }
  96. }
  97. return 0;
  98. }
  99. /* The register will be in the form [a[-b].]x[-y] */
  100. static int extract_reg_range(char *input, int *devadlo, int *devadhi,
  101. int *reglo, int *reghi)
  102. {
  103. char *regstr;
  104. /* use strrchr to find the last string after a '.' */
  105. regstr = strrchr(input, '.');
  106. /* If it exists, extract the devad(s) */
  107. if (regstr) {
  108. char devadstr[32];
  109. strncpy(devadstr, input, regstr - input);
  110. devadstr[regstr - input] = '\0';
  111. if (extract_range(devadstr, devadlo, devadhi))
  112. return -1;
  113. regstr++;
  114. } else {
  115. /* Otherwise, we have no devad, and we just got regs */
  116. *devadlo = *devadhi = MDIO_DEVAD_NONE;
  117. regstr = input;
  118. }
  119. return extract_range(regstr, reglo, reghi);
  120. }
  121. static int extract_phy_range(char *const argv[], int argc, struct mii_dev **bus,
  122. struct phy_device **phydev,
  123. int *addrlo, int *addrhi)
  124. {
  125. struct phy_device *dev = *phydev;
  126. if ((argc < 1) || (argc > 2))
  127. return -1;
  128. /* If there are two arguments, it's busname addr */
  129. if (argc == 2) {
  130. *bus = miiphy_get_dev_by_name(argv[0]);
  131. if (!*bus)
  132. return -1;
  133. return extract_range(argv[1], addrlo, addrhi);
  134. }
  135. /* It must be one argument, here */
  136. /*
  137. * This argument can be one of two things:
  138. * 1) Ethernet device name
  139. * 2) Just an address (use the previously-used bus)
  140. *
  141. * We check all buses for a PHY which is connected to an ethernet
  142. * device by the given name. If none are found, we call
  143. * extract_range() on the string, and see if it's an address range.
  144. */
  145. dev = mdio_phydev_for_ethname(argv[0]);
  146. if (dev) {
  147. *addrlo = *addrhi = dev->addr;
  148. *bus = dev->bus;
  149. return 0;
  150. }
  151. /* It's an address or nothing useful */
  152. return extract_range(argv[0], addrlo, addrhi);
  153. }
  154. /* ---------------------------------------------------------------- */
  155. static int do_mdio(struct cmd_tbl *cmdtp, int flag, int argc,
  156. char *const argv[])
  157. {
  158. char op[2];
  159. int addrlo, addrhi, reglo, reghi, devadlo, devadhi;
  160. unsigned short data;
  161. int pos = argc - 1;
  162. struct mii_dev *bus;
  163. struct phy_device *phydev = NULL;
  164. int extended = 0;
  165. if (argc < 2)
  166. return CMD_RET_USAGE;
  167. #ifdef CONFIG_DM_MDIO
  168. /* probe DM MII device before any operation so they are all accesible */
  169. dm_mdio_probe_devices();
  170. #endif
  171. /*
  172. * We use the last specified parameters, unless new ones are
  173. * entered.
  174. */
  175. op[0] = argv[1][0];
  176. addrlo = last_addr_lo;
  177. addrhi = last_addr_hi;
  178. devadlo = last_devad_lo;
  179. devadhi = last_devad_hi;
  180. reglo = last_reg_lo;
  181. reghi = last_reg_hi;
  182. data = last_data;
  183. bus = mdio_get_current_dev();
  184. if (flag & CMD_FLAG_REPEAT)
  185. op[0] = last_op[0];
  186. if (strlen(argv[1]) > 1) {
  187. op[1] = argv[1][1];
  188. if (op[1] == 'x') {
  189. phydev = mdio_phydev_for_ethname(argv[2]);
  190. if (phydev) {
  191. addrlo = phydev->addr;
  192. addrhi = addrlo;
  193. bus = phydev->bus;
  194. extended = 1;
  195. } else {
  196. return CMD_RET_FAILURE;
  197. }
  198. if (!phydev->drv ||
  199. (!phydev->drv->writeext && (op[0] == 'w')) ||
  200. (!phydev->drv->readext && (op[0] == 'r'))) {
  201. puts("PHY does not have extended functions\n");
  202. return CMD_RET_FAILURE;
  203. }
  204. }
  205. }
  206. switch (op[0]) {
  207. case 'w':
  208. if (pos > 1)
  209. data = hextoul(argv[pos--], NULL);
  210. /* Intentional fall-through - Get reg for read and write */
  211. case 'r':
  212. if (pos > 1)
  213. if (extract_reg_range(argv[pos--], &devadlo, &devadhi,
  214. &reglo, &reghi))
  215. return CMD_RET_FAILURE;
  216. /* Intentional fall-through - Get phy for all commands */
  217. default:
  218. if (pos > 1)
  219. if (extract_phy_range(&argv[2], pos - 1, &bus,
  220. &phydev, &addrlo, &addrhi))
  221. return CMD_RET_FAILURE;
  222. break;
  223. }
  224. if (!bus) {
  225. puts("No MDIO bus found\n");
  226. return CMD_RET_FAILURE;
  227. }
  228. if (op[0] == 'l') {
  229. mdio_list_devices();
  230. return 0;
  231. }
  232. /* Save the chosen bus */
  233. miiphy_set_current_dev(bus->name);
  234. switch (op[0]) {
  235. case 'w':
  236. mdio_write_ranges(bus, addrlo, addrhi, devadlo, devadhi,
  237. reglo, reghi, data, extended);
  238. break;
  239. case 'r':
  240. mdio_read_ranges(bus, addrlo, addrhi, devadlo, devadhi,
  241. reglo, reghi, extended);
  242. break;
  243. }
  244. /*
  245. * Save the parameters for repeats.
  246. */
  247. last_op[0] = op[0];
  248. last_addr_lo = addrlo;
  249. last_addr_hi = addrhi;
  250. last_devad_lo = devadlo;
  251. last_devad_hi = devadhi;
  252. last_reg_lo = reglo;
  253. last_reg_hi = reghi;
  254. last_data = data;
  255. return 0;
  256. }
  257. /***************************************************/
  258. U_BOOT_CMD(
  259. mdio, 6, 1, do_mdio,
  260. "MDIO utility commands",
  261. "list - List MDIO buses\n"
  262. "mdio read <phydev> [<devad>.]<reg> - "
  263. "read PHY's register at <devad>.<reg>\n"
  264. "mdio write <phydev> [<devad>.]<reg> <data> - "
  265. "write PHY's register at <devad>.<reg>\n"
  266. "mdio rx <phydev> [<devad>.]<reg> - "
  267. "read PHY's extended register at <devad>.<reg>\n"
  268. "mdio wx <phydev> [<devad>.]<reg> <data> - "
  269. "write PHY's extended register at <devad>.<reg>\n"
  270. "<phydev> may be:\n"
  271. " <busname> <addr>\n"
  272. " <addr>\n"
  273. " <eth name>\n"
  274. "<addr> <devad>, and <reg> may be ranges, e.g. 1-5.4-0x1f.\n"
  275. );