revert between 56095 -> 55830 in arch
[AROS.git] / workbench / devs / networks / fec / fec_hardware.c
blob1f25c03de736239734accced141ac3cd864e2323
1 /*
2 * fec_hardware.c
4 * Created on: May 21, 2009
5 * Author: misc
6 */
7 #define DEBUG 1
9 #include <aros/debug.h>
11 #include <asm/io.h>
14 #include <proto/exec.h>
15 #include <inttypes.h>
17 #include "fec.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)
31 int tries = 100;
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)
43 FEC_UDelay(unit, 10);
46 if (tries == 0)
47 return -1;
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;
55 int tries = 100;
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)
67 FEC_UDelay(unit, 10);
70 if (tries == 0)
71 return -1;
72 else
73 return 0;
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)
84 int8_t phy = 0;
85 int8_t result = -1;
87 for (phy=0; phy < 32; phy++)
89 int stat = FEC_MDIO_Read(unit, phy, 1);
90 if (stat != -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",
96 phy, stat, advert));
98 result = phy;
100 break;
105 return result;
108 int FEC_PHY_Link(struct FECUnit *unit)
110 uint16_t reg;
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)
116 return 1;
117 else
118 return 0;
122 * FEC_PHY_Reset - Try to reset the PHY. Returns 0 on failure.
124 int FEC_PHY_Reset(struct FECUnit *unit)
126 uint16_t reg;
127 uint32_t loop_cnt;
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);
133 loop_cnt = 0;
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"));
145 return 0;
147 else
148 return 1;
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;
166 else
167 return (bmcr & PHY_BMCR_100MB) ? _100BASET : _10BASET;
170 /* Check duplex */
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)
192 uint16_t bmcr;
193 uint16_t adv;
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 |
198 PHY_ANLPAR_10);
199 FEC_MDIO_Write(unit, unit->feu_phy_id, PHY_ANAR, adv);
201 adv = FEC_MDIO_Read(unit, unit->feu_phy_id, PHY_1000BTCR);
202 adv |= 0x0300;
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)
213 int i;
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)
220 break;
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 */
246 FEC_PHY_Init(unit);
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])
256 outl_be(0, ptr);
257 ptr++;
259 outl_be(0, &unit->feu_regs->mib_control);