ccdbebfca243d7e61cd7a0e42aba0ef0ea024a8f
[oweals/u-boot_mod.git] / u-boot / board / ar7240 / common / athr_s27_phy.c
1 /*
2  * Copyright (c) 2013 Qualcomm Atheros, Inc.
3  *
4  * See file CREDITS for list of people who contributed to this
5  * project.
6  *
7  * This program is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License as
9  * published by the Free Software Foundation; either version 2 of
10  * the License, or (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software
19  * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
20  * MA 02111-1307 USA
21  */
22
23 /*
24  * Manage the atheros ethernet PHY.
25  *
26  * All definitions in this file are operating system independent!
27  */
28
29 #include <config.h>
30 #include <linux/types.h>
31 #include <common.h>
32 #include <miiphy.h>
33
34 #include <asm/addrspace.h>
35 #include <atheros.h>
36 #include "athr_s27_phy.h"
37
38
39 //#include "phy.h" !!!!!!!!!!!!!!!!!!!!!!!!!!!!!
40 #define ath_gmac_unit2name(_unit) (_unit ?  "eth1" : "eth0")
41
42 extern int ath_gmac_miiphy_read(char *devname, uint32_t phaddr, uint8_t reg, uint16_t *data);
43 extern int ath_gmac_miiphy_write(char *devname, uint32_t phaddr, uint8_t reg, uint16_t data);
44
45 void athrs27_reg_rmw(unsigned int s27_addr, unsigned int s27_write_data);
46
47 #define phy_reg_read(base, addr, reg)   \
48         ath_gmac_miiphy_read(ath_gmac_unit2name(base), addr, reg, NULL)
49
50 #define phy_reg_write(base, addr, reg, data)    \
51         ath_gmac_miiphy_write(ath_gmac_unit2name(base), addr, reg, data)
52
53
54 #ifdef S27_PHY_DEBUG
55         #undef S27_PHY_DEBUG
56 #endif
57
58
59
60
61 /* PHY selections and access functions */
62
63 typedef enum {
64     PHY_SRCPORT_INFO,
65     PHY_PORTINFO_SIZE,
66 } PHY_CAP_TYPE;
67
68 typedef enum {
69     PHY_SRCPORT_NONE,
70     PHY_SRCPORT_VLANTAG,
71     PHY_SRCPORT_TRAILER,
72 } PHY_SRCPORT_TYPE;
73
74 #define DRV_LOG(DBG_SW, X0, X1, X2, X3, X4, X5, X6)
75 #define DRV_MSG(x,a,b,c,d,e,f)
76 #define DRV_PRINT(DBG_SW,X)
77
78 #define ATHR_LAN_PORT_VLAN          1
79 #define ATHR_WAN_PORT_VLAN          2
80 #define ENET_UNIT_LAN 1
81 #define ENET_UNIT_WAN 0
82
83 #define TRUE    1
84 #define FALSE   0
85
86 #define ATHR_PHY0_ADDR   0x0
87 #define ATHR_PHY1_ADDR   0x1
88 #define ATHR_PHY2_ADDR   0x2
89 #define ATHR_PHY3_ADDR   0x3
90 #define ATHR_PHY4_ADDR   0x4
91
92 #define MODULE_NAME "ATHRS27"
93
94 /*
95  * Track per-PHY port information.
96  */
97
98
99 typedef struct {
100     BOOL   isEnetPort;       /* normal enet port */
101     BOOL   isPhyAlive;       /* last known state of link */
102     int    ethUnit;          /* MAC associated with this phy port */
103     uint32_t phyBase;
104     uint32_t phyAddr;          /* PHY registers associated with this phy port */
105     uint32_t VLANTableSetting; /* Value to be written to VLAN table */
106 } athrPhyInfo_t;
107
108 /*
109  * Per-PHY information, indexed by PHY unit number.
110  */
111 static athrPhyInfo_t athrPhyInfo[] = {
112
113     {TRUE,   /* port 1 -- LAN port 1 */
114      FALSE,
115      ENET_UNIT_LAN,
116      0,
117      ATHR_PHY0_ADDR,
118      ATHR_LAN_PORT_VLAN
119     },
120
121     {TRUE,   /* port 2 -- LAN port 2 */
122      FALSE,
123      ENET_UNIT_LAN,
124      0,
125      ATHR_PHY1_ADDR,
126      ATHR_LAN_PORT_VLAN
127     },
128
129     {TRUE,   /* port 3 -- LAN port 3 */
130      FALSE,
131      ENET_UNIT_LAN,
132      0,
133      ATHR_PHY2_ADDR,
134      ATHR_LAN_PORT_VLAN
135     },
136
137
138    {TRUE,   /* port 4 --  LAN port 4 */
139      FALSE,
140      ENET_UNIT_LAN,
141      0,
142      ATHR_PHY3_ADDR,
143      ATHR_LAN_PORT_VLAN   /* Send to all ports */
144     },
145
146     {TRUE,  /* port 5 -- WAN Port 5 */
147      FALSE,
148      ENET_UNIT_WAN,
149      0,
150      ATHR_PHY4_ADDR,
151      ATHR_LAN_PORT_VLAN    /* Send to all ports */
152     },
153
154     {FALSE,   /* port 0 -- cpu port 0 */
155      TRUE,
156      ENET_UNIT_LAN,
157      0,
158      0x00,
159      ATHR_LAN_PORT_VLAN
160     },
161
162 };
163
164
165 #define ATHR_GLOBALREGBASE    0
166
167 #define ATHR_PHY_MAX 5
168
169 /* Range of valid PHY IDs is [MIN..MAX] */
170 #define ATHR_ID_MIN 0
171 #define ATHR_ID_MAX (ATHR_PHY_MAX-1)
172
173
174 /* Convenience macros to access myPhyInfo */
175 #define ATHR_IS_ENET_PORT(phyUnit) (athrPhyInfo[phyUnit].isEnetPort)
176 #define ATHR_IS_PHY_ALIVE(phyUnit) (athrPhyInfo[phyUnit].isPhyAlive)
177 #define ATHR_ETHUNIT(phyUnit) (athrPhyInfo[phyUnit].ethUnit)
178 #define ATHR_PHYBASE(phyUnit) (athrPhyInfo[phyUnit].phyBase)
179 #define ATHR_PHYADDR(phyUnit) (athrPhyInfo[phyUnit].phyAddr)
180 #define ATHR_VLAN_TABLE_SETTING(phyUnit) (athrPhyInfo[phyUnit].VLANTableSetting)
181
182
183 #define ATHR_IS_ETHUNIT(phyUnit, ethUnit) \
184             (ATHR_IS_ENET_PORT(phyUnit) &&        \
185             ATHR_ETHUNIT(phyUnit) == (ethUnit))
186
187 #define ATHR_IS_WAN_PORT(phyUnit) (!(ATHR_ETHUNIT(phyUnit)==ENET_UNIT_LAN))
188
189 /* Forward references */
190 BOOL athrs27_phy_is_link_alive(int phyUnit);
191 uint32_t athrs27_reg_read(uint32_t reg_addr);
192 void athrs27_reg_write(uint32_t reg_addr, uint32_t reg_val);
193 unsigned int s27_rd_phy(unsigned int phy_addr, unsigned int reg_addr);
194 void s27_wr_phy(unsigned int phy_addr, unsigned int reg_addr, unsigned int write_data);
195
196
197 void athrs27_powersave_off(int phy_addr)
198 {
199     s27_wr_phy(phy_addr,ATHR_DEBUG_PORT_ADDRESS,0x29);
200     s27_wr_phy(phy_addr,ATHR_DEBUG_PORT_DATA,0x36c0);
201
202 }
203 void athrs27_sleep_off(int phy_addr)
204 {
205     s27_wr_phy(phy_addr,ATHR_DEBUG_PORT_ADDRESS,0xb);
206     s27_wr_phy(phy_addr,ATHR_DEBUG_PORT_DATA,0x3c00);
207 }
208
209 void athrs27_force_100M(int phyAddr,int duplex)
210 {
211    /*
212     *  Force MDI and MDX to alternate ports 
213     *  Phy 0,2 and 4 -- MDI
214     *  Phy 1 and 3 -- MDX
215     */
216
217     if(phyAddr%2) {
218         s27_wr_phy(phyAddr,ATHR_PHY_FUNC_CONTROL,0x820);
219     }
220     else {
221         s27_wr_phy(phyAddr,ATHR_PHY_FUNC_CONTROL,0x800);
222     }
223
224     s27_wr_phy(phyAddr,0x1d,0x29);
225     s27_wr_phy(phyAddr,0x1e,0x0);
226     s27_wr_phy(phyAddr,0x10,0xc60);
227     s27_wr_phy(phyAddr,ATHR_PHY_CONTROL,(0xa000|(duplex << 8)));
228 }
229
230 void athrs27_force_10M(int phyAddr,int duplex)
231 {
232
233     athrs27_powersave_off(phyAddr);
234     athrs27_sleep_off(phyAddr);
235
236     s27_wr_phy(phyAddr,ATHR_PHY_CONTROL,(0x8000 |(duplex << 8)));
237 }
238
239 int athrs27_reg_init(void)
240 {
241 #ifdef S27_PHY_DEBUG
242     uint32_t rd_val;
243 #endif
244
245     /* if using header for register configuration, we have to     */
246     /* configure s27 register after frame transmission is enabled */
247     athrs27_reg_rmw(0x8,(1<<28));  /* Set WAN port is connected to GE0 */
248
249 #if defined(S27_FORCE_100M)
250     athrs27_force_100M(ATHR_PHY4_ADDR,1);
251 #elif  defined(S27_FORCE_10M)
252     athrs27_force_10M(ATHR_PHY4_ADDR,1);
253 #else
254     s27_wr_phy(ATHR_PHY4_ADDR,ATHR_PHY_CONTROL,0x9000);
255
256 #endif
257 #ifdef S27_PHY_DEBUG
258     printf(MODULE_NAME":OPERATIONAL_MODE_REG0:%x\n",athrs27_reg_read(OPERATIONAL_MODE_REG0));
259     printf(MODULE_NAME":REG 0x4-->:%x\n",athrs27_reg_read(0x4));
260     printf(MODULE_NAME":REG 0x2c-->:%x\n",athrs27_reg_read(0x2c));
261     printf(MODULE_NAME":REG 0x8-->:%x\n",athrs27_reg_read(0x8));
262 #endif
263
264     return 0;
265 }
266  
267 int athrs27_reg_init_lan(void)
268 {
269     int i = 60;
270 #if S26_PHY_DEBUG
271     uint32_t rd_val;
272 #endif
273     int       phyUnit;
274     uint32_t  phyAddr = 0;
275
276
277     /* reset switch */
278     //printf(MODULE_NAME ": resetting s27\n");
279     athrs27_reg_write(0x0, athrs27_reg_read(0x0)|0x80000000);
280
281     while(i--) {
282         //sysMsDelay(100);
283         if(!(athrs27_reg_read(0x0)&0x80000000))
284             break;
285     }
286     //printf(MODULE_NAME ": s27 reset done\n");
287     athrs27_reg_write(PORT_STATUS_REGISTER0,0x4e);
288
289     athrs27_reg_rmw(OPERATIONAL_MODE_REG0,(1<<6));  /* Set GMII mode */
290
291     if (is_emu() || is_wasp()) {
292        athrs27_reg_rmw(0x2c,((1<<26)| (1<<16) | 0x1)); /* FiX ME: EBU debug */
293     }
294
295     for (phyUnit=0; phyUnit < ATHR_PHY_MAX; phyUnit++) {
296
297         phyAddr = ATHR_PHYADDR(phyUnit);
298
299 #if defined(S27_FORCE_100M)
300         athrs27_force_100M(phyAddr,1);
301 #elif defined(S27_FORCE_10M)
302         athrs27_force_10M(phyAddr,1);
303 #else
304         s27_wr_phy(phyAddr,ATHR_PHY_CONTROL,0x9000);
305 #endif
306
307 #ifdef S27_PHY_DEBUG
308         rd_val = s27_rd_phy(phyAddr,ATHR_PHY_FUNC_CONTROL);
309         printf("S27 ATHR_PHY_FUNC_CONTROL (%d):%x\n",phyAddr,rd_val);
310         rd_val = s27_rd_phy(phyAddr,ATHR_PHY_ID1);
311         printf("S27 PHY ID  (%d) :%x\n",phyAddr, rd_val);
312         rd_val = s27_rd_phy(phyAddr,ATHR_PHY_SPEC_STATUS);
313         printf("S27 PHY CTRL  (%d) :%x\n",phyAddr, rd_val);
314         rd_val = s27_rd_phy(phyAddr,ATHR_PHY_STATUS);
315         printf("S27 ATHR PHY STATUS  (%d) :%x\n",phyAddr, rd_val);
316 #endif
317     }
318
319     /* 
320      * status[1:0]=2'h2;   - (0x10 - 1000 Mbps , 0x01 - 100Mbps, 0x0 - 10 Mbps)
321      * status[2]=1'h1;     - Tx Mac En
322      * status[3]=1'h1;     - Rx Mac En
323      * status[4]=1'h1;     - Tx Flow Ctrl En
324      * status[5]=1'h1;     - Rx Flow Ctrl En
325      * status[6]=1'h1;     - Duplex Mode
326      */
327     athrs27_reg_write(PORT_STATUS_REGISTER1, 0x200);  /* LAN - 1 */
328     athrs27_reg_write(PORT_STATUS_REGISTER2, 0x200);  /* LAN - 2 */
329     athrs27_reg_write(PORT_STATUS_REGISTER3, 0x200);  /* LAN - 3 */
330     athrs27_reg_write(PORT_STATUS_REGISTER4, 0x200);  /* LAN - 4 */
331
332     if (is_emu()) {
333         athrs27_reg_write(PORT_STATUS_REGISTER1, 0x4C);  /* LAN - 1 */
334         athrs27_reg_write(PORT_STATUS_REGISTER2, 0x4c);  /* LAN - 2 */
335         athrs27_reg_write(PORT_STATUS_REGISTER3, 0x4c);  /* LAN - 3 */
336         athrs27_reg_write(PORT_STATUS_REGISTER4, 0x4c);  /* LAN - 4 */
337     }
338
339     /* QM Control */
340     athrs27_reg_write(0x38, 0xc000050e);
341
342     /*
343      * status[11]=1'h0;    - CPU Disable
344      * status[7] = 1'b1;   - Learn One Lock
345      * status[14] = 1'b0;  - Learn Enable
346      */
347 #ifdef ATHEROS_HEADER_EN
348     athrs27_reg_write(PORT_CONTROL_REGISTER0, 0x4804);
349 #else
350    /* Atheros Header Disable */
351     athrs27_reg_write(PORT_CONTROL_REGISTER0, 0x4004);
352 #endif
353
354     /* Tag Priority Mapping */
355     athrs27_reg_write(0x70, 0xfa50);
356
357     /* Enable ARP packets to CPU port */
358     athrs27_reg_write(S27_ARL_TBL_CTRL_REG,(athrs27_reg_read(S27_ARL_TBL_CTRL_REG) | 0x100000));
359
360    /* Enable Broadcast packets to CPU port */
361     athrs27_reg_write(S27_FLD_MASK_REG,(athrs27_reg_read(S27_FLD_MASK_REG) |
362                            S27_ENABLE_CPU_BROADCAST | S27_ENABLE_CPU_BCAST_FWD ));
363
364     return 0;
365 }
366
367 /******************************************************************************
368 *
369 * athrs27_phy_is_link_alive - test to see if the specified link is alive
370 *
371 * RETURNS:
372 *    TRUE  --> link is alive
373 *    FALSE --> link is down
374 */
375 BOOL
376 athrs27_phy_is_link_alive(int phyUnit)
377 {
378     uint16_t phyHwStatus;
379     uint32_t phyAddr;
380
381     phyAddr = ATHR_PHYADDR(phyUnit);
382     phyHwStatus = s27_rd_phy(phyAddr, ATHR_PHY_SPEC_STATUS);
383
384     if (phyHwStatus & ATHR_STATUS_LINK_PASS)
385         return TRUE;
386
387     return FALSE;
388 }
389
390 /******************************************************************************
391 *
392 * athrs27_phy_setup - reset and setup the PHY associated with
393 * the specified MAC unit number.
394 *   
395 * Resets the associated PHY port.
396 *   
397 * RETURNS:
398 *    TRUE  --> associated PHY is alive
399 *    FALSE --> no LINKs on this ethernet unit
400 */
401 BOOL
402 athrs27_phy_setup(int ethUnit)
403 {
404     int       phyUnit;
405     uint16_t  phyHwStatus;
406     uint16_t  timeout;
407     int       liveLinks = 0;
408     BOOL      foundPhy = FALSE;
409     uint32_t  phyAddr = 0;
410
411     /* See if there's any configuration data for this enet */
412     /* start auto negogiation on each phy */
413     for (phyUnit=0; phyUnit < ATHR_PHY_MAX; phyUnit++) {
414
415         foundPhy = TRUE;
416         phyAddr = ATHR_PHYADDR(phyUnit);
417
418         if (!ATHR_IS_ETHUNIT(phyUnit, ethUnit)) {
419             continue;
420         }
421         if (!is_emu()) {
422            s27_wr_phy(phyAddr, ATHR_AUTONEG_ADVERT,ATHR_ADVERTISE_ALL);
423
424            s27_wr_phy(phyAddr, ATHR_PHY_CONTROL,ATHR_CTRL_AUTONEGOTIATION_ENABLE
425                          | ATHR_CTRL_SOFTWARE_RESET);
426         }
427         else  {
428                 //printf("############ is emulation ############\n");
429
430            if(ATHR_ETHUNIT(phyUnit) == ENET_UNIT_WAN) {
431                s27_wr_phy(phyAddr, ATHR_AUTONEG_ADVERT,ATHR_ADVERTISE_ALL);
432                s27_wr_phy(phyAddr,0x9, 0x0); //donot advertise 1000Mbps mode
433                s27_wr_phy(phyAddr, ATHR_PHY_CONTROL,0x0);
434                s27_wr_phy(phyAddr, ATHR_PHY_CONTROL,ATHR_CTRL_AUTONEGOTIATION_ENABLE
435                          | ATHR_CTRL_SOFTWARE_RESET);
436            }
437            else { 
438
439                s27_wr_phy(phyAddr, ATHR_AUTONEG_ADVERT,(ATHR_ADVERTISE_ASYM_PAUSE | ATHR_ADVERTISE_PAUSE |
440                             ATHR_ADVERTISE_10HALF | ATHR_ADVERTISE_10FULL));
441                s27_wr_phy(phyAddr,0x9, 0x0); //donot advertise 1000Mbps mode
442                s27_wr_phy(phyAddr, ATHR_PHY_CONTROL,0x0);
443                s27_wr_phy(phyAddr, ATHR_PHY_CONTROL,ATHR_CTRL_AUTONEGOTIATION_ENABLE
444                          | ATHR_CTRL_SOFTWARE_RESET);
445            }
446        }
447     }
448     if (!foundPhy) {
449         return FALSE; /* No PHY's configured for this ethUnit */
450     }
451
452     /*
453      * After the phy is reset, it takes a little while before
454      * it can respond properly.
455      */
456         /*
457     if (ethUnit == ENET_UNIT_LAN)
458         sysMsDelay(100);
459     else
460         sysMsDelay(300);
461         */
462
463     /*
464      * Wait up to 3 seconds for ALL associated PHYs to finish
465      * autonegotiation.  The only way we get out of here sooner is
466      * if ALL PHYs are connected AND finish autonegotiation.
467      */
468     for (phyUnit=0; (phyUnit < ATHR_PHY_MAX) /*&& (timeout > 0) */; phyUnit++) {
469         if (ATHR_ETHUNIT(phyUnit) == ENET_UNIT_WAN)
470             continue;
471
472         timeout=20;
473         for (;;) {
474             phyHwStatus =  s27_rd_phy(phyAddr, ATHR_PHY_CONTROL);
475
476             if (ATHR_RESET_DONE(phyHwStatus)) {
477                 DRV_PRINT(DRV_DEBUG_PHYSETUP,
478                           ("Port %d, Neg Success\n", phyUnit));
479                 break;
480             }
481             if (timeout == 0) {
482                 DRV_PRINT(DRV_DEBUG_PHYSETUP,
483                           ("Port %d, Negogiation timeout\n", phyUnit));
484                 break;
485             }
486             if (--timeout == 0) {
487                 DRV_PRINT(DRV_DEBUG_PHYSETUP,
488                           ("Port %d, Negogiation timeout\n", phyUnit));
489                 break;
490             }
491
492             //sysMsDelay(150);
493         }
494         /* extend the cable length */
495         s27_wr_phy(phyUnit, ATHR_DEBUG_PORT_ADDRESS, 0x14);
496         s27_wr_phy(phyUnit, ATHR_DEBUG_PORT_DATA, 0xf52);
497
498        /* Force Class A setting phys */
499         s27_wr_phy(phyUnit, ATHR_DEBUG_PORT_ADDRESS, 4);
500         s27_wr_phy(phyUnit, ATHR_DEBUG_PORT_DATA, 0xebbb);
501         s27_wr_phy(phyUnit, ATHR_DEBUG_PORT_ADDRESS, 5);
502         s27_wr_phy(phyUnit, ATHR_DEBUG_PORT_DATA, 0x2c47);
503
504         /* fine-tune PHYs */
505         s27_wr_phy(phyUnit, ATHR_DEBUG_PORT_ADDRESS, 0x3c);
506         s27_wr_phy(phyUnit, ATHR_DEBUG_PORT_DATA, 0x1c1);
507         s27_wr_phy(phyUnit, ATHR_DEBUG_PORT_ADDRESS, 0x37);
508         s27_wr_phy(phyUnit, ATHR_DEBUG_PORT_DATA, 0xd600);
509
510
511 #ifdef S27_VER_1_0
512         /* turn off power saving */
513         s27_wr_phy(phyUnit, 29, 41);
514         s27_wr_phy(phyUnit, 30, 0);
515         //printf("def_ S27_VER_1_0\n");
516 #endif
517     }
518
519     /*
520      * All PHYs have had adequate time to autonegotiate.
521      * Now initialize software status.
522      *
523      * It's possible that some ports may take a bit longer
524      * to autonegotiate; but we can't wait forever.  They'll
525      * get noticed by mv_phyCheckStatusChange during regular
526      * polling activities.
527      */
528     for (phyUnit=0; phyUnit < ATHR_PHY_MAX; phyUnit++) {
529         if (!ATHR_IS_ETHUNIT(phyUnit, ethUnit)) {
530             continue;
531         }
532
533         if (athrs27_phy_is_link_alive(phyUnit)) {
534             liveLinks++;
535             ATHR_IS_PHY_ALIVE(phyUnit) = TRUE;
536         } else {
537             ATHR_IS_PHY_ALIVE(phyUnit) = FALSE;
538         }
539         DRV_PRINT(DRV_DEBUG_PHYSETUP,
540             ("eth%d: Phy Specific Status=%4.4x\n",
541             ethUnit,
542             s27_rd_phy(ATHR_PHYADDR(phyUnit),ATHR_PHY_SPEC_STATUS)));
543     }
544
545     return (liveLinks > 0);
546 }
547
548 /******************************************************************************
549 *
550 * athrs27_phy_is_fdx - Determines whether the phy ports associated with the
551 * specified device are FULL or HALF duplex.
552 *
553 * RETURNS:
554 *    1 --> FULL
555 *    0 --> HALF
556 */
557 int
558 athrs27_phy_is_fdx(int ethUnit,int phyUnit)
559 {
560     uint32_t  phyAddr;
561     uint16_t  phyHwStatus;
562     int       ii = 200;
563
564     if (ethUnit == ENET_UNIT_LAN)
565         return TRUE;
566
567     for (phyUnit=0; phyUnit < ATHR_PHY_MAX; phyUnit++) {
568         if (!ATHR_IS_ETHUNIT(phyUnit, ethUnit)) {
569             continue;
570         }
571
572         if (athrs27_phy_is_link_alive(phyUnit)) {
573
574             phyAddr = ATHR_PHYADDR(phyUnit);
575
576             do {
577                 phyHwStatus = s27_rd_phy (phyAddr, ATHR_PHY_SPEC_STATUS);
578                         if(phyHwStatus & ATHR_STATUS_RESOVLED)
579                                 break;
580                 sysMsDelay(10);
581             } while(--ii);
582             if (phyHwStatus & ATHER_STATUS_FULL_DUPLEX) {
583                 return TRUE;
584             }
585         }
586     }
587
588     return FALSE;
589 }
590 /******************************************************************************
591 *
592 * athrs27_phy_speed - Determines the speed of phy ports associated with the
593 * specified device.
594 *
595 * RETURNS:
596 *               ATHR_PHY_SPEED_10T, AG7240_PHY_SPEED_100T;
597 *               ATHR_PHY_SPEED_1000T;
598 */
599
600 int
601 athrs27_phy_speed(int ethUnit,int phyUnit)
602 {
603     uint16_t  phyHwStatus;
604     uint32_t  phyAddr;
605     int       ii = 200;
606     int       phySpeed = _100BASET;
607     for (phyUnit=0; phyUnit < ATHR_PHY_MAX; phyUnit++) {
608         if (!ATHR_IS_ETHUNIT(phyUnit, ethUnit)) {
609             continue;
610         }
611
612         phyAddr = ATHR_PHYADDR(phyUnit);
613         phySpeed = _10BASET;
614
615         if (athrs27_phy_is_link_alive(phyUnit)) {
616
617             do {
618                 phyHwStatus = s27_rd_phy(phyAddr,
619                                               ATHR_PHY_SPEC_STATUS);
620                         if(phyHwStatus & ATHR_STATUS_RESOVLED)
621                                 break;
622                 sysMsDelay(10);
623             }while(--ii);
624
625             phyHwStatus = ((phyHwStatus & ATHER_STATUS_LINK_MASK) >>
626                            ATHER_STATUS_LINK_SHIFT);
627
628             switch(phyHwStatus) {
629             case 0:
630                 phySpeed = _10BASET;
631                 break;
632             case 1:
633                 phySpeed = _100BASET;
634                 break;
635             case 2:
636                 phySpeed = _1000BASET;
637                 break;
638             default:
639                 printf("Unkown speed read!\n");
640             }
641         }
642
643         phy_reg_write(1,phyAddr, ATHR_DEBUG_PORT_ADDRESS, 0x18);
644
645         if(phySpeed == _100BASET) {
646             phy_reg_write(1,phyAddr, ATHR_DEBUG_PORT_DATA, 0xba8);
647         } else {
648             phy_reg_write(1,phyAddr, ATHR_DEBUG_PORT_DATA, 0x2ea);
649         }
650     }
651
652     if (ethUnit == ENET_UNIT_LAN)
653          phySpeed = _1000BASET;
654
655     return phySpeed;
656 }
657
658 /*****************************************************************************
659 *
660 * athr_phy_is_up -- checks for significant changes in PHY state.
661 *
662 * A "significant change" is:
663 *     dropped link (e.g. ethernet cable unplugged) OR
664 *     autonegotiation completed + link (e.g. ethernet cable plugged in)
665 *
666 * When a PHY is plugged in, phyLinkGained is called.
667 * When a PHY is unplugged, phyLinkLost is called.
668 */
669
670 int
671 athrs27_phy_is_up(int ethUnit)
672 {
673
674     uint16_t      phyHwStatus, phyHwControl;
675     athrPhyInfo_t *lastStatus;
676     int           linkCount   = 0;
677     int           lostLinks   = 0;
678     int           gainedLinks = 0;
679     uint32_t      phyAddr;
680     int           phyUnit;
681
682     for (phyUnit=0; phyUnit < ATHR_PHY_MAX; phyUnit++) {
683         if (!ATHR_IS_ETHUNIT(phyUnit, ethUnit)) {
684             continue;
685         }
686
687         phyAddr = ATHR_PHYADDR(phyUnit);
688
689         lastStatus = &athrPhyInfo[phyUnit];
690         if (lastStatus->isPhyAlive) { /* last known link status was ALIVE */
691             phyHwStatus = s27_rd_phy(phyAddr, ATHR_PHY_SPEC_STATUS);
692
693             /* See if we've lost link */
694             if (phyHwStatus & ATHR_STATUS_LINK_PASS) {
695                 linkCount++;
696             } else {
697                 lostLinks++;
698                 DRV_PRINT(DRV_DEBUG_PHYCHANGE,("\nenet%d port%d down\n",
699                                                ethUnit, phyUnit));
700                 printf("enet%d port%d down\n",ethUnit, phyUnit);
701                 lastStatus->isPhyAlive = FALSE;
702             }
703         } else { /* last known link status was DEAD */
704             /* Check for reset complete */
705             if(is_emu())
706             {
707                 phyHwStatus = s27_rd_phy(phyAddr, ATHR_PHY_STATUS);
708                 if(phyAddr%2) {
709                     s27_wr_phy(phyAddr,ATHR_PHY_FUNC_CONTROL,0x820);
710                 }
711                 else {
712                     s27_wr_phy(phyAddr,ATHR_PHY_FUNC_CONTROL,0x800);
713                 }
714
715                 if((phyHwStatus & 0x4)==0)
716                 {
717                    s27_wr_phy(phyAddr,0x9,0x0);
718                    if(phyAddr !=0x4)
719                        s27_wr_phy(phyAddr,0x4,0x41);
720                    s27_wr_phy(phyAddr,0x0,0x9000);
721                 }
722             }
723
724             phyHwStatus = s27_rd_phy(phyAddr, ATHR_PHY_CONTROL);
725             if (!ATHR_RESET_DONE(phyHwStatus))
726                 continue;
727
728              phyHwControl = s27_rd_phy(phyAddr, ATHR_PHY_CONTROL);
729              phyHwStatus = s27_rd_phy(phyAddr, ATHR_PHY_STATUS);
730
731             /* Check for AutoNegotiation complete */
732             if ((!(phyHwControl & ATHR_CTRL_AUTONEGOTIATION_ENABLE))
733                  || ATHR_AUTONEG_DONE(phyHwStatus)) {
734                 phyHwStatus = s27_rd_phy(phyAddr,
735                                            ATHR_PHY_SPEC_STATUS);
736
737                 if (phyHwStatus & ATHR_STATUS_LINK_PASS) {
738                 gainedLinks++;
739                 linkCount++;
740                 printf("enet%d port%d up\n",ethUnit, phyUnit);
741                 DRV_PRINT(DRV_DEBUG_PHYCHANGE,("\nenet%d port%d up\n",
742                                                ethUnit, phyUnit));
743                 lastStatus->isPhyAlive = TRUE;
744                 }
745             }
746         }
747     }
748     return (linkCount);
749 }
750
751 unsigned int athrs27_reg_read(unsigned int s27_addr)
752 {
753     unsigned int addr_temp;
754     unsigned int s27_rd_csr_low, s27_rd_csr_high, s27_rd_csr;
755     unsigned int data,unit = 0;
756     unsigned int phy_address, reg_address;
757
758     addr_temp = s27_addr >>2;
759     data = addr_temp >> 7;
760
761     phy_address = 0x1f;
762     reg_address = 0x10;
763
764     if (is_ar7240()) {
765         unit = 0;
766     }
767     else if(is_ar7241() || is_ar7242() || is_wasp() || is_qca953x() || is_qca956x()) {
768         unit = 1;
769     }
770
771     phy_reg_write(unit,phy_address, reg_address, data);
772
773     phy_address = (0x17 & ((addr_temp >> 4) | 0x10));
774     reg_address = ((addr_temp << 1) & 0x1e);
775     s27_rd_csr_low = (uint32_t) phy_reg_read(unit,phy_address, reg_address);
776
777     reg_address = reg_address | 0x1;
778     s27_rd_csr_high = (uint32_t) phy_reg_read(unit,phy_address, reg_address);
779     s27_rd_csr = (s27_rd_csr_high << 16) | s27_rd_csr_low ;
780         
781     return(s27_rd_csr);
782 }
783
784 void athrs27_reg_write(unsigned int s27_addr, unsigned int s27_write_data)
785 {
786     unsigned int addr_temp;
787     unsigned int data;
788     unsigned int phy_address, reg_address,unit = 0;
789
790     addr_temp = (s27_addr ) >>2;
791     data = addr_temp >> 7;
792
793     phy_address = 0x1f;
794     reg_address = 0x10;
795
796     if (is_ar7240()) {
797         unit = 0;
798     }
799     else if(is_ar7241() || is_ar7242() || is_wasp() || is_qca953x() || is_qca956x()) {
800         unit = 1;
801     }
802     phy_reg_write(unit,phy_address, reg_address, data);
803
804     phy_address = (0x17 & ((addr_temp >> 4) | 0x10));
805
806     reg_address = (((addr_temp << 1) & 0x1e) | 0x1);
807     data = (s27_write_data >> 16) & 0xffff;
808     phy_reg_write(unit,phy_address, reg_address, data);
809
810     reg_address = ((addr_temp << 1) & 0x1e);
811     data = s27_write_data  & 0xffff;
812     phy_reg_write(unit,phy_address, reg_address, data);
813
814 }
815
816 void athrs27_reg_rmw(unsigned int s27_addr, unsigned int s27_write_data)
817 {
818     int val = athrs27_reg_read(s27_addr);
819     athrs27_reg_write(s27_addr,(val | s27_write_data));
820 }
821
822 unsigned int s27_rd_phy(unsigned int phy_addr, unsigned int reg_addr)
823 {
824   int unit, val = 0; 
825   
826   if (is_ar7240()) {
827     unit = 0;
828   } else if(is_ar7241() || is_ar7242() || is_wasp() || is_qca953x() || is_qca956x()) {
829     unit = 1;
830   }
831   val = (uint32_t) phy_reg_read(unit, phy_addr, reg_addr); 
832   return val;
833 }
834
835 void s27_wr_phy(unsigned int phy_addr, unsigned int reg_addr, unsigned int write_data)
836 {
837   int unit; 
838   
839   if (is_ar7240()) {
840     unit = 0;
841   } else if(is_ar7241() || is_ar7242() || is_wasp() || is_qca953x() || is_qca956x()) {
842     unit = 1;
843   }
844   
845   phy_reg_write(unit, phy_addr, reg_addr, write_data);   
846 }
847 int athrs27_mdc_check(void)
848 {
849     int i;
850
851     for (i=0; i<4000; i++) {
852         if(athrs27_reg_read(0x10c) != 0x18007fff)
853             return -1;
854     }
855     return 0;
856 }
857