Commit 0a16ea593355d1a0fd415286089961f9c9ad1614

Authored by Albert ARIBAUD
Committed by Prafulla Wadaskar
1 parent 136846d77f

mv88e61xx: refactor PHY and SWITCH level-code

Signed-off-by: Albert ARIBAUD <albert.u.boot@aribaud.net>

Showing 3 changed files with 358 additions and 197 deletions Side-by-side Diff

drivers/net/phy/mv88e61xx.c
... ... @@ -26,6 +26,14 @@
26 26 #include <netdev.h>
27 27 #include "mv88e61xx.h"
28 28  
  29 +/*
  30 + * Uncomment either of the following line for local debug control;
  31 + * otherwise global debug control will apply.
  32 + */
  33 +
  34 +/* #undef DEBUG */
  35 +/* #define DEBUG */
  36 +
29 37 #ifdef CONFIG_MV88E61XX_MULTICHIP_ADRMODE
30 38 /* Chip Address mode
31 39 * The Switch support two modes of operation
... ... @@ -52,7 +60,8 @@
52 60 return 0;
53 61 }
54 62  
55   -static void mv88e61xx_wr_phy(char *name, u32 phy_adr, u32 reg_ofs, u16 data)
  63 +static void mv88e61xx_switch_write(char *name, u32 phy_adr,
  64 + u32 reg_ofs, u16 data)
56 65 {
57 66 u16 mii_dev_addr;
58 67  
... ... @@ -70,7 +79,8 @@
70 79 15));
71 80 }
72 81  
73   -static void mv88e61xx_rd_phy(char *name, u32 phy_adr, u32 reg_ofs, u16 * data)
  82 +static void mv88e61xx_switch_read(char *name, u32 phy_adr,
  83 + u32 reg_ofs, u16 *data)
74 84 {
75 85 u16 mii_dev_addr;
76 86  
77 87  
78 88  
79 89  
... ... @@ -90,112 +100,53 @@
90 100 }
91 101 #endif /* CONFIG_MV88E61XX_MULTICHIP_ADRMODE */
92 102  
93   -static void mv88e61xx_port_vlan_config(struct mv88e61xx_config *swconfig,
94   - u32 max_prtnum, u32 ports_ofs)
95   -{
96   - u32 prt;
97   - u16 reg;
98   - char *name = swconfig->name;
99   - u32 cpu_port = swconfig->cpuport;
100   - u32 port_mask = swconfig->ports_enabled;
101   - enum mv88e61xx_cfg_vlan vlancfg = swconfig->vlancfg;
  103 +/*
  104 + * Convenience macros for switch device/port reads/writes
  105 + * These macros output valid 'mv88e61xx' U_BOOT_CMDs
  106 + */
102 107  
103   - /* be sure all ports are disabled */
104   - for (prt = 0; prt < max_prtnum; prt++) {
105   - RD_PHY(name, ports_ofs + prt, MV88E61XX_PRT_CTRL_REG, &reg);
106   - reg &= ~0x3;
107   - WR_PHY(name, ports_ofs + prt, MV88E61XX_PRT_CTRL_REG, reg);
108   -
109   - if (!(cpu_port & (1 << prt)))
110   - continue;
111   - /* Set CPU port VID to 0x1 */
112   - RD_PHY(name, (ports_ofs + prt), MV88E61XX_PRT_VID_REG, &reg);
113   - reg &= ~0xfff;
114   - reg |= 0x1;
115   - WR_PHY(name, (ports_ofs + prt), MV88E61XX_PRT_VID_REG, reg);
116   - }
117   -
118   - /* Setting Port default priority for all ports to zero */
119   - for (prt = 0; prt < max_prtnum; prt++) {
120   - RD_PHY(name, ports_ofs + prt, MV88E61XX_PRT_VID_REG, &reg);
121   - reg &= ~0xc000;
122   - WR_PHY(name, ports_ofs + prt, MV88E61XX_PRT_VID_REG, reg);
123   - }
124   - /* Setting VID and VID map for all ports except CPU port */
125   - for (prt = 0; prt < max_prtnum; prt++) {
126   - /* only for enabled ports */
127   - if ((1 << prt) & port_mask) {
128   - /* skip CPU port */
129   - if ((1 << prt) & cpu_port) {
130   - /*
131   - * Set Vlan map table for cpu_port to see
132   - * all ports
133   - */
134   - RD_PHY(name, (ports_ofs + prt),
135   - MV88E61XX_PRT_VMAP_REG, &reg);
136   - reg &= ~((1 << max_prtnum) - 1);
137   - reg |= port_mask & ~(1 << prt);
138   - WR_PHY(name, (ports_ofs + prt),
139   - MV88E61XX_PRT_VMAP_REG, reg);
140   - } else {
141   -
142   - /*
143   - * set Ports VLAN Mapping.
144   - * port prt <--> cpu_port VLAN #prt+1.
145   - */
146   - RD_PHY(name, ports_ofs + prt,
147   - MV88E61XX_PRT_VID_REG, &reg);
148   - reg &= ~0x0fff;
149   - reg |= (prt + 1);
150   - WR_PHY(name, ports_ofs + prt,
151   - MV88E61XX_PRT_VID_REG, reg);
152   -
153   - RD_PHY(name, ports_ofs + prt,
154   - MV88E61XX_PRT_VMAP_REG, &reg);
155   - if (vlancfg == MV88E61XX_VLANCFG_DEFAULT) {
156   - /*
157   - * all any port can send frames to all other ports
158   - * ref: sec 3.2.1.1 of datasheet
159   - */
160   - reg |= 0x03f;
161   - reg &= ~(1 << prt);
162   - } else if (vlancfg == MV88E61XX_VLANCFG_ROUTER) {
163   - /*
164   - * all other ports can send frames to CPU port only
165   - * ref: sec 3.2.1.2 of datasheet
166   - */
167   - reg &= ~((1 << max_prtnum) - 1);
168   - reg |= cpu_port;
169   - }
170   - WR_PHY(name, ports_ofs + prt,
171   - MV88E61XX_PRT_VMAP_REG, reg);
172   - }
173   - }
174   - }
175   -
176   - /*
177   - * enable only appropriate ports to forwarding mode
178   - * and disable the others
179   - */
180   - for (prt = 0; prt < max_prtnum; prt++) {
181   - if ((1 << prt) & port_mask) {
182   - RD_PHY(name, ports_ofs + prt,
183   - MV88E61XX_PRT_CTRL_REG, &reg);
184   - reg |= 0x3;
185   - WR_PHY(name, ports_ofs + prt,
186   - MV88E61XX_PRT_CTRL_REG, reg);
187   - } else {
188   - /* Disable port */
189   - RD_PHY(name, ports_ofs + prt,
190   - MV88E61XX_PRT_CTRL_REG, &reg);
191   - reg &= ~0x3;
192   - WR_PHY(name, ports_ofs + prt,
193   - MV88E61XX_PRT_CTRL_REG, reg);
194   - }
195   - }
  108 +#ifndef DEBUG
  109 +#define WR_SWITCH_REG wr_switch_reg
  110 +#define RD_SWITCH_REG rd_switch_reg
  111 +#define WR_SWITCH_PORT_REG(n, p, r, d) \
  112 + WR_SWITCH_REG(n, (MV88E61XX_PRT_OFST+p), r, d)
  113 +#define RD_SWITCH_PORT_REG(n, p, r, d) \
  114 + RD_SWITCH_REG(n, (MV88E61XX_PRT_OFST+p), r, d)
  115 +#else
  116 +static void WR_SWITCH_REG(char *name, u32 dev_adr, u32 reg_ofs, u16 data)
  117 +{
  118 + printf("mv88e61xx %s dev %02x reg %02x write %04x\n",
  119 + name, dev_adr, reg_ofs, data);
  120 + wr_switch_reg(name, dev_adr, reg_ofs, data);
196 121 }
  122 +static void RD_SWITCH_REG(char *name, u32 dev_adr, u32 reg_ofs, u16 *data)
  123 +{
  124 + rd_switch_reg(name, dev_adr, reg_ofs, data);
  125 + printf("mv88e61xx %s dev %02x reg %02x read %04x\n",
  126 + name, dev_adr, reg_ofs, *data);
  127 +}
  128 +static void WR_SWITCH_PORT_REG(char *name, u32 prt_adr, u32 reg_ofs,
  129 + u16 data)
  130 +{
  131 + printf("mv88e61xx %s port %02x reg %02x write %04x\n",
  132 + name, prt_adr, reg_ofs, data);
  133 + wr_switch_reg(name, (MV88E61XX_PRT_OFST+prt_adr), reg_ofs, data);
  134 +}
  135 +static void RD_SWITCH_PORT_REG(char *name, u32 prt_adr, u32 reg_ofs,
  136 + u16 *data)
  137 +{
  138 + rd_switch_reg(name, (MV88E61XX_PRT_OFST+prt_adr), reg_ofs, data);
  139 + printf("mv88e61xx %s port %02x reg %02x read %04x\n",
  140 + name, prt_adr, reg_ofs, *data);
  141 +}
  142 +#endif
197 143  
198 144 /*
  145 + * Local functions to read/write registers on the switch PHYs.
  146 + * NOTE! This goes through switch, not direct miiphy, writes and reads!
  147 + */
  148 +
  149 +/*
199 150 * Make sure SMIBusy bit cleared before another
200 151 * SMI operation can take place
201 152 */
... ... @@ -204,7 +155,7 @@
204 155 u16 reg = 0;
205 156 u32 timeout = MV88E61XX_PHY_TIMEOUT;
206 157 do {
207   - RD_PHY(name, MV88E61XX_GLB2REG_DEVADR,
  158 + rd_switch_reg(name, MV88E61XX_GLB2REG_DEVADR,
208 159 MV88E61XX_PHY_CMD, &reg);
209 160 if (timeout-- == 0) {
210 161 printf("SMI busy timeout\n");
211 162  
212 163  
213 164  
214 165  
215 166  
... ... @@ -214,34 +165,110 @@
214 165 return 0;
215 166 }
216 167  
  168 +static inline int mv88e61xx_switch_miiphy_write(char *name, u32 phy,
  169 + u32 reg, u16 data)
  170 +{
  171 + /* write switch data reg then cmd reg then check completion */
  172 + wr_switch_reg(name, MV88E61XX_GLB2REG_DEVADR, MV88E61XX_PHY_DATA,
  173 + data);
  174 + wr_switch_reg(name, MV88E61XX_GLB2REG_DEVADR, MV88E61XX_PHY_CMD,
  175 + (MV88E61XX_PHY_WRITE_CMD | (phy << 5) | reg));
  176 + return mv88e61xx_busychk(name);
  177 +}
  178 +
  179 +static inline int mv88e61xx_switch_miiphy_read(char *name, u32 phy,
  180 + u32 reg, u16 *data)
  181 +{
  182 + /* write switch cmd reg, check for completion */
  183 + wr_switch_reg(name, MV88E61XX_GLB2REG_DEVADR, MV88E61XX_PHY_CMD,
  184 + (MV88E61XX_PHY_READ_CMD | (phy << 5) | reg));
  185 + if (mv88e61xx_busychk(name))
  186 + return -1;
  187 + /* read switch data reg and return success */
  188 + rd_switch_reg(name, MV88E61XX_GLB2REG_DEVADR, MV88E61XX_PHY_DATA, data);
  189 + return 0;
  190 +}
  191 +
217 192 /*
  193 + * Convenience macros for switch PHY reads/writes
  194 + */
  195 +
  196 +#ifndef DEBUG
  197 +#define WR_SWITCH_PHY_REG mv88e61xx_switch_miiphy_write
  198 +#define RD_SWITCH_PHY_REG mv88e61xx_switch_miiphy_read
  199 +#else
  200 +static inline int WR_SWITCH_PHY_REG(char *name, u32 phy_adr,
  201 + u32 reg_ofs, u16 data)
  202 +{
  203 + int r = mv88e61xx_switch_miiphy_write(name, phy_adr, reg_ofs, data);
  204 + if (r)
  205 + printf("** ERROR writing mv88e61xx %s phy %02x reg %02x\n",
  206 + name, phy_adr, reg_ofs);
  207 + else
  208 + printf("mv88e61xx %s phy %02x reg %02x write %04x\n",
  209 + name, phy_adr, reg_ofs, data);
  210 + return r;
  211 +}
  212 +static inline int RD_SWITCH_PHY_REG(char *name, u32 phy_adr,
  213 + u32 reg_ofs, u16 *data)
  214 +{
  215 + int r = mv88e61xx_switch_miiphy_read(name, phy_adr, reg_ofs, data);
  216 + if (r)
  217 + printf("** ERROR reading mv88e61xx %s phy %02x reg %02x\n",
  218 + name, phy_adr, reg_ofs);
  219 + else
  220 + printf("mv88e61xx %s phy %02x reg %02x read %04x\n",
  221 + name, phy_adr, reg_ofs, *data);
  222 + return r;
  223 +}
  224 +#endif
  225 +
  226 +static void mv88e61xx_port_vlan_config(struct mv88e61xx_config *swconfig)
  227 +{
  228 + u32 prt;
  229 + u16 reg;
  230 + char *name = swconfig->name;
  231 + u32 port_mask = swconfig->ports_enabled;
  232 +
  233 + /* apply internal vlan config */
  234 + for (prt = 0; prt < MV88E61XX_MAX_PORTS_NUM; prt++) {
  235 + /* only for enabled ports */
  236 + if ((1 << prt) & port_mask) {
  237 + /* take vlan map from swconfig */
  238 + u8 vlanmap = swconfig->vlancfg[prt];
  239 + /* remove disabled ports from vlan map */
  240 + vlanmap &= swconfig->ports_enabled;
  241 + /* apply vlan map to port */
  242 + RD_SWITCH_PORT_REG(name, prt,
  243 + MV88E61XX_PRT_VMAP_REG, &reg);
  244 + reg &= ~((1 << MV88E61XX_MAX_PORTS_NUM) - 1);
  245 + reg |= vlanmap;
  246 + WR_SWITCH_PORT_REG(name, prt,
  247 + MV88E61XX_PRT_VMAP_REG, reg);
  248 + }
  249 + }
  250 +}
  251 +
  252 +/*
218 253 * Power up the specified port and reset PHY
219 254 */
220   -static int mv88361xx_powerup(struct mv88e61xx_config *swconfig, u32 prt)
  255 +static int mv88361xx_powerup(struct mv88e61xx_config *swconfig, u32 phy)
221 256 {
222 257 char *name = swconfig->name;
223 258  
224   - /* Write Copper Specific control reg1 (0x14) for-
  259 + /* Write Copper Specific control reg1 (0x10) for-
225 260 * Enable Phy power up
226 261 * Energy Detect on (sense&Xmit NLP Periodically
227 262 * reset other settings default
228 263 */
229   - WR_PHY(name, MV88E61XX_GLB2REG_DEVADR, MV88E61XX_PHY_DATA, 0x3360);
230   - WR_PHY(name, MV88E61XX_GLB2REG_DEVADR,
231   - MV88E61XX_PHY_CMD, (0x9410 | (prt << 5)));
232   -
233   - if (mv88e61xx_busychk(name))
  264 + if (WR_SWITCH_PHY_REG(name, phy, 0x10, 0x3360))
234 265 return -1;
235 266  
236 267 /* Write PHY ctrl reg (0x0) to apply
237 268 * Phy reset (set bit 15 low)
238 269 * reset other default values
239 270 */
240   - WR_PHY(name, MV88E61XX_GLB2REG_DEVADR, MV88E61XX_PHY_DATA, 0x1140);
241   - WR_PHY(name, MV88E61XX_GLB2REG_DEVADR,
242   - MV88E61XX_PHY_CMD, (0x9400 | (prt << 5)));
243   -
244   - if (mv88e61xx_busychk(name))
  271 + if (WR_SWITCH_PHY_REG(name, phy, 0x00, 0x9140))
245 272 return -1;
246 273  
247 274 return 0;
248 275  
249 276  
250 277  
251 278  
... ... @@ -256,48 +283,26 @@
256 283 * to setup PHY LEDs default configuration to detect 10/100/1000Mb/s
257 284 * Link status
258 285 */
259   -static int mv88361xx_led_init(struct mv88e61xx_config *swconfig, u32 prt)
  286 +static int mv88361xx_led_init(struct mv88e61xx_config *swconfig, u32 phy)
260 287 {
261 288 char *name = swconfig->name;
262   - u16 reg;
263 289  
264 290 if (swconfig->led_init != MV88E61XX_LED_INIT_EN)
265 291 return 0;
266 292  
267 293 /* set page address to 3 */
268   - reg = 3;
269   - WR_PHY(name, MV88E61XX_GLB2REG_DEVADR, MV88E61XX_PHY_DATA, reg);
270   - WR_PHY(name, MV88E61XX_GLB2REG_DEVADR,
271   - MV88E61XX_PHY_CMD, (1 << MV88E61XX_BUSY_OFST |
272   - 1 << MV88E61XX_MODE_OFST |
273   - 1 << MV88E61XX_OP_OFST |
274   - prt << MV88E61XX_ADDR_OFST | 22));
275   -
276   - if (mv88e61xx_busychk(name))
  294 + if (WR_SWITCH_PHY_REG(name, phy, 0x16, 0x0003))
277 295 return -1;
278 296  
279   - /* set LED Func Ctrl reg */
280   - reg = 1; /* LED[0] On-Link, Blink-Activity, Off-NoLink */
281   - WR_PHY(name, MV88E61XX_GLB2REG_DEVADR, MV88E61XX_PHY_DATA, reg);
282   - WR_PHY(name, MV88E61XX_GLB2REG_DEVADR,
283   - MV88E61XX_PHY_CMD, (1 << MV88E61XX_BUSY_OFST |
284   - 1 << MV88E61XX_MODE_OFST |
285   - 1 << MV88E61XX_OP_OFST |
286   - prt << MV88E61XX_ADDR_OFST | 16));
287   -
288   - if (mv88e61xx_busychk(name))
  297 + /*
  298 + * set LED Func Ctrl reg
  299 + * value 0x0001 = LED[0] On-Link, Blink-Activity, Off-NoLink
  300 + */
  301 + if (WR_SWITCH_PHY_REG(name, phy, 0x10, 0x0001))
289 302 return -1;
290 303  
291 304 /* set page address to 0 */
292   - reg = 0;
293   - WR_PHY(name, MV88E61XX_GLB2REG_DEVADR, MV88E61XX_PHY_DATA, reg);
294   - WR_PHY(name, MV88E61XX_GLB2REG_DEVADR,
295   - MV88E61XX_PHY_CMD, (1 << MV88E61XX_BUSY_OFST |
296   - 1 << MV88E61XX_MODE_OFST |
297   - 1 << MV88E61XX_OP_OFST |
298   - prt << MV88E61XX_ADDR_OFST | 22));
299   -
300   - if (mv88e61xx_busychk(name))
  305 + if (WR_SWITCH_PHY_REG(name, phy, 0x16, 0x0000))
301 306 return -1;
302 307  
303 308 return 0;
304 309  
305 310  
... ... @@ -312,23 +317,15 @@
312 317 * This is optional settings may be needed on some boards
313 318 * for PHY<->magnetics h/w tuning
314 319 */
315   -static int mv88361xx_reverse_mdipn(struct mv88e61xx_config *swconfig, u32 prt)
  320 +static int mv88361xx_reverse_mdipn(struct mv88e61xx_config *swconfig, u32 phy)
316 321 {
317 322 char *name = swconfig->name;
318   - u16 reg;
319 323  
320 324 if (swconfig->mdip != MV88E61XX_MDIP_REVERSE)
321 325 return 0;
322 326  
323   - reg = 0x0f; /*Reverse MDIP/N[3:0] bits */
324   - WR_PHY(name, MV88E61XX_GLB2REG_DEVADR, MV88E61XX_PHY_DATA, reg);
325   - WR_PHY(name, MV88E61XX_GLB2REG_DEVADR,
326   - MV88E61XX_PHY_CMD, (1 << MV88E61XX_BUSY_OFST |
327   - 1 << MV88E61XX_MODE_OFST |
328   - 1 << MV88E61XX_OP_OFST |
329   - prt << MV88E61XX_ADDR_OFST | 20));
330   -
331   - if (mv88e61xx_busychk(name))
  327 + /*Reverse MDIP/N[3:0] bits */
  328 + if (WR_SWITCH_PHY_REG(name, phy, 0x14, 0x000f))
332 329 return -1;
333 330  
334 331 return 0;
... ... @@ -343,6 +340,7 @@
343 340 u16 reg;
344 341 char *idstr;
345 342 char *name = swconfig->name;
  343 + int time;
346 344  
347 345 if (miiphy_set_current_dev(name)) {
348 346 printf("%s failed\n", __FUNCTION__);
... ... @@ -354,7 +352,7 @@
354 352 printf("Invalid cpu port config, using default port5\n");
355 353 }
356 354  
357   - RD_PHY(name, MV88E61XX_PRT_OFST, MII_PHYSID2, &reg);
  355 + RD_SWITCH_PORT_REG(name, 0, MII_PHYSID2, &reg);
358 356 switch (reg &= 0xfff0) {
359 357 case 0x1610:
360 358 idstr = "88E6161";
361 359  
362 360  
363 361  
364 362  
365 363  
366 364  
367 365  
368 366  
369 367  
... ... @@ -373,47 +371,184 @@
373 371 break;
374 372 }
375 373  
376   - /* Port based VLANs configuration */
377   - if ((swconfig->vlancfg == MV88E61XX_VLANCFG_DEFAULT)
378   - || (swconfig->vlancfg == MV88E61XX_VLANCFG_ROUTER))
379   - mv88e61xx_port_vlan_config(swconfig, MV88E61XX_MAX_PORTS_NUM,
380   - MV88E61XX_PRT_OFST);
381   - else {
382   - printf("Unsupported mode %s failed\n", __FUNCTION__);
383   - return -1;
  374 + /* be sure all ports are disabled */
  375 + for (prt = 0; prt < MV88E61XX_MAX_PORTS_NUM; prt++) {
  376 + RD_SWITCH_PORT_REG(name, prt, MV88E61XX_PRT_CTRL_REG, &reg);
  377 + reg &= ~0x3;
  378 + WR_SWITCH_PORT_REG(name, prt, MV88E61XX_PRT_CTRL_REG, reg);
384 379 }
385 380  
  381 + /* wait 2 ms for queues to drain */
  382 + udelay(2000);
  383 +
  384 + /* reset switch */
  385 + RD_SWITCH_REG(name, MV88E61XX_GLBREG_DEVADR, MV88E61XX_SGCR, &reg);
  386 + reg |= 0x8000;
  387 + WR_SWITCH_REG(name, MV88E61XX_GLBREG_DEVADR, MV88E61XX_SGCR, reg);
  388 +
  389 + /* wait up to 1 second for switch reset complete */
  390 + for (time = 1000; time; time--) {
  391 + RD_SWITCH_REG(name, MV88E61XX_GLBREG_DEVADR, MV88E61XX_SGSR,
  392 + &reg);
  393 + if ((reg & 0xc800) == 0xc800)
  394 + break;
  395 + udelay(1000);
  396 + }
  397 + if (!time)
  398 + return -1;
  399 +
  400 + /* Port based VLANs configuration */
  401 + mv88e61xx_port_vlan_config(swconfig);
  402 +
386 403 if (swconfig->rgmii_delay == MV88E61XX_RGMII_DELAY_EN) {
387 404 /*
388 405 * Enable RGMII delay on Tx and Rx for CPU port
389 406 * Ref: sec 9.5 of chip datasheet-02
390 407 */
391   - WR_PHY(name, MV88E61XX_PRT_OFST + 5,
392   - MV88E61XX_RGMII_TIMECTRL_REG, 0x18);
393   - WR_PHY(name, MV88E61XX_PRT_OFST + 4,
394   - MV88E61XX_RGMII_TIMECTRL_REG, 0xc1e7);
  408 + /*Force port link down */
  409 + WR_SWITCH_PORT_REG(name, 5, MV88E61XX_PCS_CTRL_REG, 0x10);
  410 + /* configure port RGMII delay */
  411 + WR_SWITCH_PORT_REG(name, 4,
  412 + MV88E61XX_RGMII_TIMECTRL_REG, 0x81e7);
  413 + RD_SWITCH_PORT_REG(name, 5,
  414 + MV88E61XX_RGMII_TIMECTRL_REG, &reg);
  415 + WR_SWITCH_PORT_REG(name, 5,
  416 + MV88E61XX_RGMII_TIMECTRL_REG, reg | 0x18);
  417 + WR_SWITCH_PORT_REG(name, 4,
  418 + MV88E61XX_RGMII_TIMECTRL_REG, 0xc1e7);
  419 + /* Force port to RGMII FDX 1000Base then up */
  420 + WR_SWITCH_PORT_REG(name, 5, MV88E61XX_PCS_CTRL_REG, 0x1e);
  421 + WR_SWITCH_PORT_REG(name, 5, MV88E61XX_PCS_CTRL_REG, 0x3e);
395 422 }
396 423  
397 424 for (prt = 0; prt < MV88E61XX_MAX_PORTS_NUM; prt++) {
398   - if (!((1 << prt) & swconfig->cpuport)) {
399 425  
400   - if (mv88361xx_led_init(swconfig, prt))
  426 + /* configure port's PHY */
  427 + if (!((1 << prt) & swconfig->cpuport)) {
  428 + /* port 4 has phy 6, not 4 */
  429 + int phy = (prt == 4) ? 6 : prt;
  430 + if (mv88361xx_powerup(swconfig, phy))
401 431 return -1;
402   - if (mv88361xx_reverse_mdipn(swconfig, prt))
  432 + if (mv88361xx_reverse_mdipn(swconfig, phy))
403 433 return -1;
404   - if (mv88361xx_powerup(swconfig, prt))
  434 + if (mv88361xx_led_init(swconfig, phy))
405 435 return -1;
406 436 }
407 437  
  438 + /* set port VID to port+1 except for cpu port */
  439 + if (!((1 << prt) & swconfig->cpuport)) {
  440 + RD_SWITCH_PORT_REG(name, prt,
  441 + MV88E61XX_PRT_VID_REG, &reg);
  442 + WR_SWITCH_PORT_REG(name, prt,
  443 + MV88E61XX_PRT_VID_REG,
  444 + (reg & ~1023) | (prt+1));
  445 + }
  446 +
408 447 /*Program port state */
409   - RD_PHY(name, MV88E61XX_PRT_OFST + prt,
410   - MV88E61XX_PRT_CTRL_REG, &reg);
411   - WR_PHY(name, MV88E61XX_PRT_OFST + prt,
412   - MV88E61XX_PRT_CTRL_REG,
413   - reg | (swconfig->portstate & 0x03));
  448 + RD_SWITCH_PORT_REG(name, prt,
  449 + MV88E61XX_PRT_CTRL_REG, &reg);
  450 + WR_SWITCH_PORT_REG(name, prt,
  451 + MV88E61XX_PRT_CTRL_REG,
  452 + reg | (swconfig->portstate & 0x03));
  453 +
414 454 }
415 455  
416 456 printf("%s Initialized on %s\n", idstr, name);
417 457 return 0;
418 458 }
  459 +
  460 +#ifdef CONFIG_MV88E61XX_CMD
  461 +static int
  462 +do_switch(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
  463 +{
  464 + char *name, *endp;
  465 + int write = 0;
  466 + enum { dev, prt, phy } target = dev;
  467 + u32 addrlo, addrhi, addr;
  468 + u32 reglo, reghi, reg;
  469 + u16 data, rdata;
  470 +
  471 + if (argc < 7)
  472 + return -1;
  473 +
  474 + name = argv[1];
  475 +
  476 + if (strcmp(argv[2], "phy") == 0)
  477 + target = phy;
  478 + else if (strcmp(argv[2], "port") == 0)
  479 + target = prt;
  480 + else if (strcmp(argv[2], "dev") != 0)
  481 + return 1;
  482 +
  483 + addrlo = simple_strtoul(argv[3], &endp, 16);
  484 +
  485 + if (!*endp) {
  486 + addrhi = addrlo;
  487 + } else {
  488 + while (*endp < '0' || *endp > '9')
  489 + endp++;
  490 + addrhi = simple_strtoul(endp, NULL, 16);
  491 + }
  492 +
  493 + reglo = simple_strtoul(argv[5], &endp, 16);
  494 + if (!*endp) {
  495 + reghi = reglo;
  496 + } else {
  497 + while (*endp < '0' || *endp > '9')
  498 + endp++;
  499 + reghi = simple_strtoul(endp, NULL, 16);
  500 + }
  501 +
  502 + if (strcmp(argv[6], "write") == 0)
  503 + write = 1;
  504 + else if (strcmp(argv[6], "read") != 0)
  505 + return 1;
  506 +
  507 + data = simple_strtoul(argv[7], NULL, 16);
  508 +
  509 + for (addr = addrlo; addr <= addrhi; addr++) {
  510 + for (reg = reglo; reg <= reghi; reg++) {
  511 + if (write) {
  512 + if (target == phy)
  513 + mv88e61xx_switch_miiphy_write(
  514 + name, addr, reg, data);
  515 + else if (target == prt)
  516 + wr_switch_reg(name,
  517 + addr+MV88E61XX_PRT_OFST,
  518 + reg, data);
  519 + else
  520 + wr_switch_reg(name, addr, reg, data);
  521 + } else {
  522 + if (target == phy)
  523 + mv88e61xx_switch_miiphy_read(
  524 + name, addr, reg, &rdata);
  525 + else if (target == prt)
  526 + rd_switch_reg(name,
  527 + addr+MV88E61XX_PRT_OFST,
  528 + reg, &rdata);
  529 + else
  530 + rd_switch_reg(name, addr, reg, &rdata);
  531 + printf("%s %s %s %02x %s %02x %s %04x\n",
  532 + argv[0], argv[1], argv[2], addr,
  533 + argv[4], reg, argv[6], rdata);
  534 + if (write && argc == 7 && rdata != data)
  535 + return 1;
  536 + }
  537 + }
  538 + }
  539 + return 0;
  540 +}
  541 +
  542 +U_BOOT_CMD(mv88e61xx, 8, 0, do_switch,
  543 + "Read or write mv88e61xx switch registers",
  544 + "<ethdevice> dev|port|phy <addr> reg <reg> write <data>\n"
  545 + "<ethdevice> dev|port|phy <addr> reg <reg> read [<data>]\n"
  546 + " - read/write switch device, port or phy at (addr,reg)\n"
  547 + " addr=0..0x1C for dev, 0..5 for port or phy.\n"
  548 + " reg=0..0x1F.\n"
  549 + " data=0..0xFFFF (tested if present against actual read).\n"
  550 + " All numeric parameters are assumed to be hex.\n"
  551 + " <addr> and <<reg> arguments can be ranges (x..y)"
  552 +);
  553 +#endif /* CONFIG_MV88E61XX_CMD */
drivers/net/phy/mv88e61xx.h
... ... @@ -28,35 +28,50 @@
28 28 #include <miiphy.h>
29 29  
30 30 #define MV88E61XX_CPU_PORT 0x5
31   -#define MV88E61XX_MAX_PORTS_NUM 0x6
32 31  
33 32 #define MV88E61XX_PHY_TIMEOUT 100000
34 33  
35   -#define MV88E61XX_PRT_STS_REG 0x1
  34 +/* port dev-addr (= port + 0x10) */
  35 +#define MV88E61XX_PRT_OFST 0x10
  36 +/* port registers */
  37 +#define MV88E61XX_PCS_CTRL_REG 0x1
36 38 #define MV88E61XX_PRT_CTRL_REG 0x4
37 39 #define MV88E61XX_PRT_VMAP_REG 0x6
38 40 #define MV88E61XX_PRT_VID_REG 0x7
  41 +#define MV88E61XX_RGMII_TIMECTRL_REG 0x1A
39 42  
40   -#define MV88E61XX_PRT_OFST 0x10
  43 +/* global registers dev-addr */
  44 +#define MV88E61XX_GLBREG_DEVADR 0x1B
  45 +/* global registers */
  46 +#define MV88E61XX_SGSR 0x00
  47 +#define MV88E61XX_SGCR 0x04
  48 +
  49 +/* global 2 registers dev-addr */
  50 +#define MV88E61XX_GLB2REG_DEVADR 0x1C
  51 +/* global 2 registers */
41 52 #define MV88E61XX_PHY_CMD 0x18
42 53 #define MV88E61XX_PHY_DATA 0x19
43   -#define MV88E61XX_RGMII_TIMECTRL_REG 0x1A
44   -#define MV88E61XX_GLB2REG_DEVADR 0x1C
  54 +/* global 2 phy commands */
  55 +#define MV88E61XX_PHY_WRITE_CMD 0x9400
  56 +#define MV88E61XX_PHY_READ_CMD 0x9800
45 57  
46 58 #define MV88E61XX_BUSY_OFST 15
47 59 #define MV88E61XX_MODE_OFST 12
48   -#define MV88E61XX_OP_OFST 10
  60 +#define MV88E61XX_OP_OFST 10
49 61 #define MV88E61XX_ADDR_OFST 5
50 62  
51 63 #ifdef CONFIG_MV88E61XX_MULTICHIP_ADRMODE
52 64 static int mv88e61xx_busychk_multic(char *name, u32 devaddr);
53   -static void mv88e61xx_wr_phy(char *name, u32 phy_adr, u32 reg_ofs, u16 data);
54   -static void mv88e61xx_rd_phy(char *name, u32 phy_adr, u32 reg_ofs, u16 * data);
55   -#define WR_PHY mv88e61xx_wr_phy
56   -#define RD_PHY mv88e61xx_rd_phy
  65 +static void mv88e61xx_switch_write(char *name, u32 phy_adr,
  66 + u32 reg_ofs, u16 data);
  67 +static void mv88e61xx_switch_read(char *name, u32 phy_adr,
  68 + u32 reg_ofs, u16 *data);
  69 +#define wr_switch_reg mv88e61xx_switch_write
  70 +#define rd_switch_reg mv88e61xx_switch_read
57 71 #else
58   -#define WR_PHY miiphy_write
59   -#define RD_PHY miiphy_read
  72 +/* switch appears a s simple PHY and can thus use miiphy */
  73 +#define wr_switch_reg miiphy_write
  74 +#define rd_switch_reg miiphy_read
60 75 #endif /* CONFIG_MV88E61XX_MULTICHIP_ADRMODE */
61 76  
62 77 #endif /* _MV88E61XX_H */
... ... @@ -163,11 +163,10 @@
163 163 * the stuct and enums here are used to specify switch configuration params
164 164 */
165 165 #if defined(CONFIG_MV88E61XX_SWITCH)
166   -enum mv88e61xx_cfg_vlan {
167   - MV88E61XX_VLANCFG_DEFAULT,
168   - MV88E61XX_VLANCFG_ROUTER
169   -};
170 166  
  167 +/* constants for any 88E61xx switch */
  168 +#define MV88E61XX_MAX_PORTS_NUM 6
  169 +
171 170 enum mv88e61xx_cfg_mdip {
172 171 MV88E61XX_MDIP_NOCHANGE,
173 172 MV88E61XX_MDIP_REVERSE
... ... @@ -192,7 +191,7 @@
192 191  
193 192 struct mv88e61xx_config {
194 193 char *name;
195   - enum mv88e61xx_cfg_vlan vlancfg;
  194 + u8 vlancfg[MV88E61XX_MAX_PORTS_NUM];
196 195 enum mv88e61xx_cfg_rgmiid rgmii_delay;
197 196 enum mv88e61xx_cfg_prtstt portstate;
198 197 enum mv88e61xx_cfg_ledinit led_init;
... ... @@ -200,6 +199,18 @@
200 199 u32 ports_enabled;
201 200 u8 cpuport;
202 201 };
  202 +
  203 +/*
  204 + * Common mappings for Internal VLANs
  205 + * These mappings consider that all ports are useable; the driver
  206 + * will mask inexistent/unused ports.
  207 + */
  208 +
  209 +/* Switch mode : routes any port to any port */
  210 +#define MV88E61XX_VLANCFG_SWITCH { 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F }
  211 +
  212 +/* Router mode: routes only CPU port 5 to/from non-CPU ports 0-4 */
  213 +#define MV88E61XX_VLANCFG_ROUTER { 0x20, 0x20, 0x20, 0x20, 0x20, 0x1F }
203 214  
204 215 int mv88e61xx_switch_initialize(struct mv88e61xx_config *swconfig);
205 216 #endif /* CONFIG_MV88E61XX_SWITCH */