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