3 * This file is subject to the terms and conditions of the GNU General Public
4 * License. See the file "COPYING" in the main directory of this archive
7 * Copyright © 2007 Atheros Communications, Inc., All Rights Reserved.
11 * Manage the atheros ethernet PHY.
13 * All definitions in this file are operating system independent!
17 #include <linux/types.h>
21 #include <asm/addrspace.h>
22 #include "ar7240_soc.h"
23 #include "athrs27_phy.h"
25 /* PHY selections and access functions */
26 #define DRV_PRINT(DBG_SW,X)
28 #define ATHR_LAN_PORT_VLAN 1
29 #define ATHR_WAN_PORT_VLAN 2
30 #define ENET_UNIT_LAN 1
31 #define ENET_UNIT_WAN 0
33 #define ATHR_PHY0_ADDR 0x0
34 #define ATHR_PHY1_ADDR 0x1
35 #define ATHR_PHY2_ADDR 0x2
36 #define ATHR_PHY3_ADDR 0x3
37 #define ATHR_PHY4_ADDR 0x4
42 #define MODULE_NAME "ATHRS27"
45 * Track per-PHY port information.
48 int isEnetPort; /* normal enet port */
49 int isPhyAlive; /* last known state of link */
50 int ethUnit; /* MAC associated with this phy port */
52 uint32_t phyAddr; /* PHY registers associated with this phy port */
53 uint32_t VLANTableSetting; /* Value to be written to VLAN table */
57 * Per-PHY information, indexed by PHY unit number.
59 static athrPhyInfo_t athrPhyInfo[] = {
60 /* port 1 -- LAN port 1 */
61 { TRUE, FALSE, ENET_UNIT_LAN, 0, ATHR_PHY0_ADDR, ATHR_LAN_PORT_VLAN },
63 /* port 2 -- LAN port 2 */
64 { TRUE, FALSE, ENET_UNIT_LAN, 0, ATHR_PHY1_ADDR, ATHR_LAN_PORT_VLAN },
66 /* port 3 -- LAN port 3 */
67 { TRUE, FALSE, ENET_UNIT_LAN, 0, ATHR_PHY2_ADDR, ATHR_LAN_PORT_VLAN },
69 /* port 4 -- LAN port 4 */
70 { TRUE, FALSE, ENET_UNIT_LAN, 0, ATHR_PHY3_ADDR, ATHR_LAN_PORT_VLAN },
72 /* port 5 -- WAN Port 5 */
73 { TRUE, FALSE, ENET_UNIT_WAN, 0, ATHR_PHY4_ADDR, ATHR_LAN_PORT_VLAN },
75 /* port 0 -- cpu port 0 */
76 { FALSE, TRUE, ENET_UNIT_LAN, 0, 0x00, ATHR_LAN_PORT_VLAN },
79 #define ATHR_PHY_MAX 5
81 /* Convenience macros to access myPhyInfo */
82 #define ATHR_IS_ENET_PORT(phyUnit) (athrPhyInfo[phyUnit].isEnetPort)
83 #define ATHR_IS_PHY_ALIVE(phyUnit) (athrPhyInfo[phyUnit].isPhyAlive)
84 #define ATHR_ETHUNIT(phyUnit) (athrPhyInfo[phyUnit].ethUnit)
85 #define ATHR_PHYBASE(phyUnit) (athrPhyInfo[phyUnit].phyBase)
86 #define ATHR_PHYADDR(phyUnit) (athrPhyInfo[phyUnit].phyAddr)
87 #define ATHR_VLAN_TABLE_SETTING(phyUnit) (athrPhyInfo[phyUnit].VLANTableSetting)
88 #define ATHR_IS_ETHUNIT(phyUnit, ethUnit) (ATHR_IS_ENET_PORT(phyUnit) && ATHR_ETHUNIT(phyUnit) == (ethUnit))
89 #define ATHR_IS_WAN_PORT(phyUnit) (!(ATHR_ETHUNIT(phyUnit) == ENET_UNIT_LAN))
91 /* Forward references */
92 int athrs27_phy_is_link_alive(int phyUnit);
93 uint32_t athrs27_reg_read(uint32_t reg_addr);
94 void athrs27_reg_write(uint32_t reg_addr, uint32_t reg_val);
95 unsigned int s27_rd_phy(unsigned int phy_addr, unsigned int reg_addr);
96 void s27_wr_phy(unsigned int phy_addr, unsigned int reg_addr, unsigned int write_data);
97 void athrs27_reg_rmw(unsigned int s27_addr, unsigned int s27_write_data);
99 void athrs27_powersave_off(int phy_addr){
100 s27_wr_phy(phy_addr, ATHR_DEBUG_PORT_ADDRESS, 0x29);
101 s27_wr_phy(phy_addr, ATHR_DEBUG_PORT_DATA, 0x36c0);
104 void athrs27_sleep_off(int phy_addr){
105 s27_wr_phy(phy_addr, ATHR_DEBUG_PORT_ADDRESS, 0xb);
106 s27_wr_phy(phy_addr, ATHR_DEBUG_PORT_DATA, 0x3c00);
109 void athrs27_force_100M(int phyAddr, int duplex){
111 * Force MDI and MDX to alternate ports
112 * Phy 0,2 and 4 -- MDI
116 s27_wr_phy(phyAddr, ATHR_PHY_FUNC_CONTROL, 0x820);
118 s27_wr_phy(phyAddr, ATHR_PHY_FUNC_CONTROL, 0x800);
121 s27_wr_phy(phyAddr, 0x1d, 0x29);
122 s27_wr_phy(phyAddr, 0x1e, 0x0);
123 s27_wr_phy(phyAddr, 0x10, 0xc60);
124 s27_wr_phy(phyAddr, ATHR_PHY_CONTROL, (0xa000 | (duplex << 8)));
127 void athrs27_force_10M(int phyAddr, int duplex){
128 athrs27_powersave_off(phyAddr);
129 athrs27_sleep_off(phyAddr);
131 s27_wr_phy(phyAddr, ATHR_PHY_CONTROL, (0x8000 | (duplex << 8)));
134 int athrs27_reg_init(void){
135 /* if using header for register configuration, we have to */
136 /* configure s27 register after frame transmission is enabled */
137 athrs27_reg_rmw(0x8, (1 << 28)); /* Set WAN port is connected to GE0 */
139 #if defined(S27_FORCE_100M)
140 athrs27_force_100M(ATHR_PHY4_ADDR, 1);
141 #elif defined(S27_FORCE_10M)
142 athrs27_force_10M(ATHR_PHY4_ADDR, 1);
144 s27_wr_phy(ATHR_PHY4_ADDR,ATHR_PHY_CONTROL, 0x9000);
148 printf(MODULE_NAME":OPERATIONAL_MODE_REG0:%x\n", athrs27_reg_read(OPERATIONAL_MODE_REG0));
149 printf(MODULE_NAME":REG 0x4-->:%x\n", athrs27_reg_read(0x4));
150 printf(MODULE_NAME":REG 0x2c-->:%x\n", athrs27_reg_read(0x2c));
151 printf(MODULE_NAME":REG 0x8-->:%x\n", athrs27_reg_read(0x8));
157 int athrs27_reg_init_lan(void){
160 uint32_t phyAddr = 0;
167 printf(MODULE_NAME ": resetting s27\n");
170 athrs27_reg_write(0x0, athrs27_reg_read(0x0) | 0x80000000);
175 if(!(athrs27_reg_read(0x0) & 0x80000000)){
181 printf(MODULE_NAME ": s27 reset done\n");
184 athrs27_reg_write(PORT_STATUS_REGISTER0, 0x4e);
186 athrs27_reg_rmw(OPERATIONAL_MODE_REG0, (1 << 6)); /* Set GMII mode */
188 if(is_emu() || is_wasp()){
189 athrs27_reg_rmw(0x2c, ((1 << 26) | (1 << 16) | 0x1)); /* FiX ME: EBU debug */
192 for(phyUnit = 0; phyUnit < ATHR_PHY_MAX; phyUnit++){
193 phyAddr = ATHR_PHYADDR(phyUnit);
195 #if defined(S27_FORCE_100M)
196 athrs27_force_100M(phyAddr, 1);
197 #elif defined(S27_FORCE_10M)
198 athrs27_force_10M(phyAddr, 1);
200 s27_wr_phy(phyAddr, ATHR_PHY_CONTROL, 0x9000);
204 rd_val = s27_rd_phy(phyAddr, ATHR_PHY_FUNC_CONTROL);
205 printf("S27 ATHR_PHY_FUNC_CONTROL (%d):%x\n", phyAddr, rd_val);
207 rd_val = s27_rd_phy(phyAddr, ATHR_PHY_ID1);
208 printf("S27 PHY ID (%d) :%x\n", phyAddr, rd_val);
210 rd_val = s27_rd_phy(phyAddr, ATHR_PHY_SPEC_STATUS);
211 printf("S27 PHY CTRL (%d) :%x\n", phyAddr, rd_val);
213 rd_val = s27_rd_phy(phyAddr, ATHR_PHY_STATUS);
214 printf("S27 ATHR PHY STATUS (%d) :%x\n", phyAddr, rd_val);
219 * status[1:0]=2'h2; - (0x10 - 1000 Mbps , 0x01 - 100Mbps, 0x0 - 10 Mbps)
220 * status[2]=1'h1; - Tx Mac En
221 * status[3]=1'h1; - Rx Mac En
222 * status[4]=1'h1; - Tx Flow Ctrl En
223 * status[5]=1'h1; - Rx Flow Ctrl En
224 * status[6]=1'h1; - Duplex Mode
226 athrs27_reg_write(PORT_STATUS_REGISTER1, 0x200); /* LAN - 1 */
227 athrs27_reg_write(PORT_STATUS_REGISTER2, 0x200); /* LAN - 2 */
228 athrs27_reg_write(PORT_STATUS_REGISTER3, 0x200); /* LAN - 3 */
229 athrs27_reg_write(PORT_STATUS_REGISTER4, 0x200); /* LAN - 4 */
232 athrs27_reg_write(PORT_STATUS_REGISTER1, 0x4C); /* LAN - 1 */
233 athrs27_reg_write(PORT_STATUS_REGISTER2, 0x4c); /* LAN - 2 */
234 athrs27_reg_write(PORT_STATUS_REGISTER3, 0x4c); /* LAN - 3 */
235 athrs27_reg_write(PORT_STATUS_REGISTER4, 0x4c); /* LAN - 4 */
239 athrs27_reg_write(0x38, 0xc000050e);
242 * status[11]=1'h0; - CPU Disable
243 * status[7] = 1'b1; - Learn One Lock
244 * status[14] = 1'b0; - Learn Enable
246 #ifdef ATHEROS_HEADER_EN
247 athrs27_reg_write(PORT_CONTROL_REGISTER0, 0x4804);
249 /* Atheros Header Disable */
250 athrs27_reg_write(PORT_CONTROL_REGISTER0, 0x4004);
253 /* Tag Priority Mapping */
254 athrs27_reg_write(0x70, 0xfa50);
256 /* Enable ARP packets to CPU port */
257 athrs27_reg_write(S27_ARL_TBL_CTRL_REG, (athrs27_reg_read(S27_ARL_TBL_CTRL_REG) | 0x100000));
259 /* Enable Broadcast packets to CPU port */
260 athrs27_reg_write(S27_FLD_MASK_REG, (athrs27_reg_read(S27_FLD_MASK_REG) | S27_ENABLE_CPU_BROADCAST | S27_ENABLE_CPU_BCAST_FWD ));
265 /******************************************************************************
267 * athrs27_phy_is_link_alive - test to see if the specified link is alive
270 * TRUE --> link is alive
271 * FALSE --> link is down
273 int athrs27_phy_is_link_alive(int phyUnit){
274 uint16_t phyHwStatus;
277 phyAddr = ATHR_PHYADDR(phyUnit);
279 phyHwStatus = s27_rd_phy(phyAddr, ATHR_PHY_SPEC_STATUS);
281 if(phyHwStatus & ATHR_STATUS_LINK_PASS){
288 /******************************************************************************
290 * athrs27_phy_setup - reset and setup the PHY associated with
291 * the specified MAC unit number.
293 * Resets the associated PHY port.
296 * TRUE --> associated PHY is alive
297 * FALSE --> no LINKs on this ethernet unit
299 int athrs27_phy_setup(int ethUnit){
300 int foundPhy = FALSE;
303 uint16_t phyHwStatus;
305 uint32_t phyAddr = 0;
310 /* See if there's any configuration data for this enet */
311 /* start auto negogiation on each phy */
312 for(phyUnit = 0; phyUnit < ATHR_PHY_MAX; phyUnit++) {
314 phyAddr = ATHR_PHYADDR(phyUnit);
316 if(!ATHR_IS_ETHUNIT(phyUnit, ethUnit)){
321 s27_wr_phy(phyAddr, ATHR_AUTONEG_ADVERT, ATHR_ADVERTISE_ALL);
322 s27_wr_phy(phyAddr, ATHR_PHY_CONTROL, ATHR_CTRL_AUTONEGOTIATION_ENABLE | ATHR_CTRL_SOFTWARE_RESET);
324 if(ATHR_ETHUNIT(phyUnit) == ENET_UNIT_WAN){
325 s27_wr_phy(phyAddr, ATHR_AUTONEG_ADVERT, ATHR_ADVERTISE_ALL);
326 s27_wr_phy(phyAddr, 0x9, 0x0); //donot advertise 1000Mbps mode
327 s27_wr_phy(phyAddr, ATHR_PHY_CONTROL, 0x0);
328 s27_wr_phy(phyAddr, ATHR_PHY_CONTROL, ATHR_CTRL_AUTONEGOTIATION_ENABLE | ATHR_CTRL_SOFTWARE_RESET);
330 s27_wr_phy(phyAddr, ATHR_AUTONEG_ADVERT, (ATHR_ADVERTISE_ASYM_PAUSE | ATHR_ADVERTISE_PAUSE | ATHR_ADVERTISE_10HALF | ATHR_ADVERTISE_10FULL));
331 s27_wr_phy(phyAddr, 0x9, 0x0); //donot advertise 1000Mbps mode
332 s27_wr_phy(phyAddr, ATHR_PHY_CONTROL, 0x0);
333 s27_wr_phy(phyAddr, ATHR_PHY_CONTROL, ATHR_CTRL_AUTONEGOTIATION_ENABLE | ATHR_CTRL_SOFTWARE_RESET);
338 rd_val = s27_rd_phy(phyAddr,ATHR_PHY_CONTROL);
339 printf("%s ATHR_PHY_CONTROL %d: 0x%x\n",__func__,phyAddr,rd_val);
341 rd_val = s27_rd_phy(phyAddr,ATHR_PHY_SPEC_STATUS);
342 printf("%s ATHR_PHY_SPEC_STAUS %d: 0x%x\n",__func__,phyAddr,rd_val);
347 return(FALSE); /* No PHY's configured for this ethUnit */
351 * After the phy is reset, it takes a little while before
352 * it can respond properly.
354 if(ethUnit == ENET_UNIT_LAN){
355 sysMsDelay(100); // changed by lsz, sysMsDelay(1000);
357 sysMsDelay(300); // changed by lsz, sysMsDelay(3000);
361 * Wait up to 3 seconds for ALL associated PHYs to finish
362 * autonegotiation. The only way we get out of here sooner is
363 * if ALL PHYs are connected AND finish autonegotiation.
365 for(phyUnit = 0; phyUnit < ATHR_PHY_MAX; phyUnit++) {
366 if(ATHR_ETHUNIT(phyUnit) == ENET_UNIT_WAN){
373 phyHwStatus = s27_rd_phy(phyAddr, ATHR_PHY_CONTROL);
375 if(ATHR_RESET_DONE(phyHwStatus)){
376 DRV_PRINT(DRV_DEBUG_PHYSETUP, ("Port %d, Neg Success\n", phyUnit));
381 DRV_PRINT(DRV_DEBUG_PHYSETUP, ("Port %d, Negogiation timeout\n", phyUnit));
386 DRV_PRINT(DRV_DEBUG_PHYSETUP, ("Port %d, Negogiation timeout\n", phyUnit));
394 s27_wr_phy(phyUnit, 29, 0x14);
395 s27_wr_phy(phyUnit, 30, 0x1352);
398 /* turn off power saving */
399 s27_wr_phy(phyUnit, 29, 41);
400 s27_wr_phy(phyUnit, 30, 0);
401 printf("def_ S27_VER_1_0\n");
406 * All PHYs have had adequate time to autonegotiate.
407 * Now initialize software status.
409 * It's possible that some ports may take a bit longer
410 * to autonegotiate; but we can't wait forever. They'll
411 * get noticed by mv_phyCheckStatusChange during regular
412 * polling activities.
414 for (phyUnit = 0; phyUnit < ATHR_PHY_MAX; phyUnit++) {
415 if(!ATHR_IS_ETHUNIT(phyUnit, ethUnit)){
419 if(athrs27_phy_is_link_alive(phyUnit)){
421 ATHR_IS_PHY_ALIVE(phyUnit) = TRUE;
423 ATHR_IS_PHY_ALIVE(phyUnit) = FALSE;
426 DRV_PRINT(DRV_DEBUG_PHYSETUP, ("eth%d: Phy Specific Status=%4.4x\n", ethUnit, s27_rd_phy(ATHR_PHYADDR(phyUnit),ATHR_PHY_SPEC_STATUS)));
429 return(liveLinks > 0);
432 /******************************************************************************
434 * athrs27_phy_is_fdx - Determines whether the phy ports associated with the
435 * specified device are FULL or HALF duplex.
441 int athrs27_phy_is_fdx(int ethUnit,int phyUnit){
443 uint16_t phyHwStatus;
446 if(ethUnit == ENET_UNIT_LAN){
450 for(phyUnit = 0; phyUnit < ATHR_PHY_MAX; phyUnit++){
451 if(!ATHR_IS_ETHUNIT(phyUnit, ethUnit)){
455 if(athrs27_phy_is_link_alive(phyUnit)){
456 phyAddr = ATHR_PHYADDR(phyUnit);
459 phyHwStatus = s27_rd_phy(phyAddr, ATHR_PHY_SPEC_STATUS);
461 if(phyHwStatus & ATHR_STATUS_RESOVLED){
468 if(phyHwStatus & ATHER_STATUS_FULL_DUPLEX){
476 /******************************************************************************
478 * athrs27_phy_speed - Determines the speed of phy ports associated with the
482 * ATHR_PHY_SPEED_10T, AG7240_PHY_SPEED_100T;
483 * ATHR_PHY_SPEED_1000T;
485 int athrs27_phy_speed(int ethUnit, int phyUnit){
486 uint16_t phyHwStatus;
491 for(phyUnit = 0; phyUnit < ATHR_PHY_MAX; phyUnit++){
492 if(!ATHR_IS_ETHUNIT(phyUnit, ethUnit)){
496 phyAddr = ATHR_PHYADDR(phyUnit);
499 if(athrs27_phy_is_link_alive(phyUnit)){
501 phyHwStatus = s27_rd_phy(phyAddr, ATHR_PHY_SPEC_STATUS);
503 if(phyHwStatus & ATHR_STATUS_RESOVLED){
510 phyHwStatus = ((phyHwStatus & ATHER_STATUS_LINK_MASK) >> ATHER_STATUS_LINK_SHIFT);
517 phySpeed = _100BASET;
520 phySpeed = _1000BASET;
523 printf("## Error: unknown eth speed!\n");
527 phy_reg_write(1, phyAddr, ATHR_DEBUG_PORT_ADDRESS, 0x18);
529 if(phySpeed == _100BASET){
530 phy_reg_write(1, phyAddr, ATHR_DEBUG_PORT_DATA, 0xba8);
532 phy_reg_write(1, phyAddr, ATHR_DEBUG_PORT_DATA, 0x2ea);
536 if(ethUnit == ENET_UNIT_LAN){
537 phySpeed = _1000BASET;
543 /*****************************************************************************
545 * athr_phy_is_up -- checks for significant changes in PHY state.
547 * A "significant change" is:
548 * dropped link (e.g. ethernet cable unplugged) OR
549 * autonegotiation completed + link (e.g. ethernet cable plugged in)
551 * When a PHY is plugged in, phyLinkGained is called.
552 * When a PHY is unplugged, phyLinkLost is called.
554 int athrs27_phy_is_up(int ethUnit){
555 athrPhyInfo_t *lastStatus;
561 uint16_t phyHwStatus, phyHwControl;
563 for(phyUnit = 0; phyUnit < ATHR_PHY_MAX; phyUnit++){
564 if(!ATHR_IS_ETHUNIT(phyUnit, ethUnit)){
568 phyAddr = ATHR_PHYADDR(phyUnit);
570 lastStatus = &athrPhyInfo[phyUnit];
572 if(lastStatus->isPhyAlive){ /* last known link status was ALIVE */
573 phyHwStatus = s27_rd_phy(phyAddr, ATHR_PHY_SPEC_STATUS);
575 /* See if we've lost link */
576 if(phyHwStatus & ATHR_STATUS_LINK_PASS){
580 DRV_PRINT(DRV_DEBUG_PHYCHANGE,("\nenet%d port%d down\n", ethUnit, phyUnit));
581 lastStatus->isPhyAlive = FALSE;
583 } else { /* last known link status was DEAD */
584 /* Check for reset complete */
586 phyHwStatus = s27_rd_phy(phyAddr, ATHR_PHY_STATUS);
589 s27_wr_phy(phyAddr, ATHR_PHY_FUNC_CONTROL, 0x820);
591 s27_wr_phy(phyAddr, ATHR_PHY_FUNC_CONTROL, 0x800);
594 if((phyHwStatus & 0x4) == 0){
595 s27_wr_phy(phyAddr, 0x9, 0x0);
598 s27_wr_phy(phyAddr, 0x4, 0x41);
601 s27_wr_phy(phyAddr, 0x0, 0x9000);
605 phyHwStatus = s27_rd_phy(phyAddr, ATHR_PHY_CONTROL);
607 if(!ATHR_RESET_DONE(phyHwStatus)){
611 phyHwControl = s27_rd_phy(phyAddr, ATHR_PHY_CONTROL);
612 phyHwStatus = s27_rd_phy(phyAddr, ATHR_PHY_STATUS);
614 /* Check for AutoNegotiation complete */
615 if((!(phyHwControl & ATHR_CTRL_AUTONEGOTIATION_ENABLE)) || ATHR_AUTONEG_DONE(phyHwStatus)){
616 phyHwStatus = s27_rd_phy(phyAddr, ATHR_PHY_SPEC_STATUS);
618 if(phyHwStatus & ATHR_STATUS_LINK_PASS){
621 DRV_PRINT(DRV_DEBUG_PHYCHANGE,("\nenet%d port%d up\n", ethUnit, phyUnit));
622 lastStatus->isPhyAlive = TRUE;
631 unsigned int athrs27_reg_read(unsigned int s27_addr){
632 unsigned int addr_temp;
633 unsigned int s27_rd_csr_low, s27_rd_csr_high, s27_rd_csr;
634 unsigned int data, unit = 0;
635 unsigned int phy_address, reg_address;
637 addr_temp = s27_addr >> 2;
638 data = addr_temp >> 7;
645 } else if(is_ar7241() || is_ar7242() || is_wasp()){
649 phy_reg_write(unit, phy_address, reg_address, data);
651 phy_address = (0x17 & ((addr_temp >> 4) | 0x10));
652 reg_address = ((addr_temp << 1) & 0x1e);
653 s27_rd_csr_low = (uint32_t)phy_reg_read(unit, phy_address, reg_address);
655 reg_address = reg_address | 0x1;
656 s27_rd_csr_high = (uint32_t)phy_reg_read(unit, phy_address, reg_address);
657 s27_rd_csr = (s27_rd_csr_high << 16) | s27_rd_csr_low;
662 void athrs27_reg_write(unsigned int s27_addr, unsigned int s27_write_data){
663 unsigned int addr_temp;
665 unsigned int phy_address;
666 unsigned int reg_address,unit = 0;
668 addr_temp = (s27_addr ) >> 2;
669 data = addr_temp >> 7;
676 } else if(is_ar7241() || is_ar7242() || is_wasp()){
680 phy_reg_write(unit,phy_address, reg_address, data);
682 phy_address = (0x17 & ((addr_temp >> 4) | 0x10));
684 reg_address = (((addr_temp << 1) & 0x1e) | 0x1);
685 data = (s27_write_data >> 16) & 0xffff;
686 phy_reg_write(unit, phy_address, reg_address, data);
688 reg_address = ((addr_temp << 1) & 0x1e);
689 data = s27_write_data & 0xffff;
690 phy_reg_write(unit, phy_address, reg_address, data);
693 void athrs27_reg_rmw(unsigned int s27_addr, unsigned int s27_write_data){
694 int val = athrs27_reg_read(s27_addr);
695 athrs27_reg_write(s27_addr,(val | s27_write_data));
698 unsigned int s27_rd_phy(unsigned int phy_addr, unsigned int reg_addr){
702 /* MDIO_CMD is set for read */
703 rddata = athrs27_reg_read(0x98);
704 rddata = (rddata & 0x0) | (reg_addr << 16) | (phy_addr << 21) | (1 << 27) | (1 << 30) | (1 << 31);
705 athrs27_reg_write(0x98, rddata);
707 rddata = athrs27_reg_read(0x98);
708 rddata = rddata & (1 << 31);
710 // Check MDIO_BUSY status
712 // TODO: do we need this?
716 printf("## Error: MDIO_BUSY!\n");
720 rddata = athrs27_reg_read(0x98);
721 rddata = rddata & (1 << 31);
724 /* Read the data from phy */
725 rddata = athrs27_reg_read(0x98) & 0xffff;
730 void s27_wr_phy(unsigned int phy_addr, unsigned int reg_addr, unsigned int write_data){
734 /* MDIO_CMD is set for read */
735 rddata = athrs27_reg_read(0x98);
736 rddata = (rddata & 0x0) | (write_data & 0xffff) | (reg_addr << 16) | (phy_addr << 21) | (0 << 27) | (1 << 30) | (1 << 31);
737 athrs27_reg_write(0x98, rddata);
739 rddata = athrs27_reg_read(0x98);
740 rddata = rddata & (1 << 31);
742 // Check MDIO_BUSY status
744 // TODO: do we need this?
748 printf("## Error: MDIO_BUSY!\n");
752 rddata = athrs27_reg_read(0x98);
753 rddata = rddata & (1 << 31);
758 int athrs27_mdc_check(void){
761 for(i = 0; i < 4000; i++){
762 if(athrs27_reg_read(0x10c) != 0x18007fff){