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