4 * Created on: May 21, 2009
9 #include <aros/debug.h>
14 #include <proto/exec.h>
19 void FEC_UDelay(struct FECUnit
*unit
, uint32_t usec
)
21 unit
->feu_TimerPort
.mp_SigTask
= FindTask(NULL
);
22 unit
->feu_TimerRequest
.tr_node
.io_Command
= TR_ADDREQUEST
;
23 unit
->feu_TimerRequest
.tr_time
.tv_secs
= usec
/ 1000000;
24 unit
->feu_TimerRequest
.tr_time
.tv_micro
= usec
% 1000000;
26 DoIO((struct IORequest
*)&unit
->feu_TimerRequest
);
29 int FEC_MDIO_Read(struct FECUnit
*unit
, int32_t phy_id
, int32_t reg
)
32 uint32_t request
= FEC_MII_READ_FRAME
;
34 outl_be(FEC_IEVENT_MII
, &unit
->feu_regs
->ievent
);
36 request
|= (phy_id
<< FEC_MII_DATA_PA_SHIFT
) & FEC_MII_DATA_PA_MSK
;
37 request
|= (reg
<< FEC_MII_DATA_RA_SHIFT
) & FEC_MII_DATA_RA_MSK
;
39 outl_be(request
, &unit
->feu_regs
->mii_data
);
41 while(!(inl_be(&unit
->feu_regs
->ievent
) & FEC_IEVENT_MII
) && --tries
)
49 return inl_be(&unit
->feu_regs
->mii_data
) & FEC_MII_DATA_DATAMSK
;
52 int FEC_MDIO_Write(struct FECUnit
*unit
, int32_t phy_id
, int32_t reg
, uint16_t data
)
54 uint32_t value
= data
;
57 outl_be(FEC_IEVENT_MII
, &unit
->feu_regs
->ievent
);
59 value
|= FEC_MII_WRITE_FRAME
;
60 value
|= (phy_id
<< FEC_MII_DATA_PA_SHIFT
) & FEC_MII_DATA_PA_MSK
;
61 value
|= (reg
<< FEC_MII_DATA_RA_SHIFT
) & FEC_MII_DATA_RA_MSK
;
63 outl_be(value
, &unit
->feu_regs
->mii_data
);
65 while(!(inl_be(&unit
->feu_regs
->ievent
) & FEC_IEVENT_MII
) && --tries
)
76 void FEC_PHY_Init(struct FECUnit
*unit
)
78 /* Don't do much. Just adjust the MII speed */
79 outl_be(unit
->feu_phy_speed
, &unit
->feu_regs
->mii_speed
);
82 int8_t FEC_PHY_Find(struct FECUnit
*unit
)
87 for (phy
=0; phy
< 32; phy
++)
89 int stat
= FEC_MDIO_Read(unit
, phy
, 1);
92 if (stat
!= 0xffff && stat
!= 0x0000)
94 int advert
= FEC_MDIO_Read(unit
, phy
, 4);
95 D(bug("[FEC] MII transceiver %d status %4.4x advertising %4.4x\n",
108 int FEC_PHY_Link(struct FECUnit
*unit
)
112 FEC_MDIO_Read(unit
, unit
->feu_phy_id
, PHY_BMSR
);
113 reg
= FEC_MDIO_Read(unit
, unit
->feu_phy_id
, PHY_BMSR
);
115 if (reg
& PHY_BMSR_LS
)
122 * FEC_PHY_Reset - Try to reset the PHY. Returns 0 on failure.
124 int FEC_PHY_Reset(struct FECUnit
*unit
)
129 /* set the reset signal. It should go away automaticaly within 0.5 seconds */
130 reg
= FEC_MDIO_Read(unit
, unit
->feu_phy_id
, PHY_BMCR
) | PHY_BMCR_RESET
;
131 FEC_MDIO_Write(unit
, unit
->feu_phy_id
, PHY_BMCR
, reg
);
135 /* Wait until either BMCR_RESET goes away or the timeout (0.5s) occurs */
136 while((reg
& PHY_BMCR_RESET
) && loop_cnt
++ < 1000)
138 reg
= FEC_MDIO_Read(unit
, unit
->feu_phy_id
, PHY_BMCR
);
139 FEC_UDelay(unit
, 500);
142 if (reg
& PHY_BMCR_RESET
)
144 D(bug("[FEC] PHY Reset timed out\n"));
151 /* Get the PHY link speed */
152 int FEC_PHY_Speed(struct FECUnit
*unit
)
154 uint16_t bmcr
, anlpar
;
156 bmcr
= FEC_MDIO_Read(unit
, unit
->feu_phy_id
, PHY_BMCR
);
158 /* Check if auto negotiation is enabled */
159 if (bmcr
& PHY_BMCR_AUTON
)
161 /* Get the autonegotiation result */
162 anlpar
= FEC_MDIO_Read(unit
, unit
->feu_phy_id
, PHY_ANLPAR
);
164 return (anlpar
& PHY_ANLPAR_100
) ? _100BASET
: _10BASET
;
167 return (bmcr
& PHY_BMCR_100MB
) ? _100BASET
: _10BASET
;
171 int FEC_PHY_Duplex(struct FECUnit
*unit
)
173 uint16_t bmcr
, anlpar
;
175 bmcr
= FEC_MDIO_Read(unit
, unit
->feu_phy_id
, PHY_BMCR
);
177 /* Is autonegotiation enabled? */
178 if (bmcr
& PHY_BMCR_AUTON
)
180 anlpar
= FEC_MDIO_Read(unit
, unit
->feu_phy_id
, PHY_ANLPAR
);
182 return (anlpar
& (PHY_ANLPAR_10FD
| PHY_ANLPAR_TXFD
)) ? FULL
: HALF
;
185 return (bmcr
& PHY_BMCR_DPLX
) ? FULL
: HALF
;
189 /* Initiate autonegotiaition */
190 void FEC_PHY_Setup_Autonegotiation(struct FECUnit
*unit
)
195 adv
= FEC_MDIO_Read(unit
, unit
->feu_phy_id
, PHY_ANAR
);
196 adv
|= (PHY_ANLPAR_ACK
| PHY_ANLPAR_RF
| PHY_ANLPAR_T4
|
197 PHY_ANLPAR_TXFD
| PHY_ANLPAR_TX
| PHY_ANLPAR_10FD
|
199 FEC_MDIO_Write(unit
, unit
->feu_phy_id
, PHY_ANAR
, adv
);
201 adv
= FEC_MDIO_Read(unit
, unit
->feu_phy_id
, PHY_1000BTCR
);
203 FEC_MDIO_Write(unit
, unit
->feu_phy_id
, PHY_1000BTCR
, adv
);
205 /* Start/restart negotiation */
206 bmcr
= FEC_MDIO_Read(unit
, unit
->feu_phy_id
, PHY_BMCR
);
207 bmcr
|= (PHY_BMCR_AUTON
| PHY_BMCR_RST_NEG
);
208 FEC_MDIO_Write(unit
, unit
->feu_phy_id
, PHY_BMCR
, bmcr
);
211 void FEC_HW_Init(struct FECUnit
*unit
)
215 /* Reset the hardware */
216 outl_be(FEC_ECNTRL_RESET
, &unit
->feu_regs
->ecntrl
);
217 for (i
=0; i
< 20; i
++)
219 if ((inl_be(&unit
->feu_regs
->ecntrl
) & FEC_ECNTRL_RESET
) == 0)
222 FEC_UDelay(unit
, 10);
225 /* set pause to 0x20 frames */
226 outl_be(FEC_OP_PAUSE_OPCODE
| 0x20, &unit
->feu_regs
->op_pause
);
228 /* high service request will be deasserted when there's < 7 bytes in fifo
229 * low service request will be deasserted when there's < 4*7 bytes in fifo
231 outl_be(FEC_FIFO_CNTRL_FRAME
| FEC_FIFO_CNTRL_LTG_7
, &unit
->feu_regs
->rfifo_cntrl
);
232 outl_be(FEC_FIFO_CNTRL_FRAME
| FEC_FIFO_CNTRL_LTG_7
, &unit
->feu_regs
->tfifo_cntrl
);
234 /* alarm when <= x bytes in FIFO */
235 outl_be(0x0000030c, &unit
->feu_regs
->rfifo_alarm
);
236 outl_be(0x00000100, &unit
->feu_regs
->tfifo_alarm
);
238 /* begin transmittion when 256 bytes are in FIFO (or EOF or FIFO full) */
239 outl_be(FEC_FIFO_WMRK_256B
, &unit
->feu_regs
->x_wmrk
);
241 /* enable crc generation */
242 outl_be(FEC_XMIT_FSM_APPEND_CRC
| FEC_XMIT_FSM_ENABLE_CRC
, &unit
->feu_regs
->xmit_fsm
);
243 outl_be(0x00000000, &unit
->feu_regs
->iaddr1
); /* No individual filter */
244 outl_be(0x00000000, &unit
->feu_regs
->iaddr2
); /* No individual filter */
249 void FEC_Reset_Stats(struct FECUnit
*unit
)
251 uint32_t *ptr
= &unit
->feu_regs
->rmon_t_drop
;
253 outl_be(FEC_MIB_DISABLE
, &unit
->feu_regs
->mib_control
);
254 while (ptr
< &unit
->feu_regs
->reserved10
[0])
259 outl_be(0, &unit
->feu_regs
->mib_control
);