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