4 * Ingenic Semiconductor, <jlwei@ingenic.cn>
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License as
8 * published by the Free Software Foundation; either version 2 of
9 * the License, or (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
23 #if defined(CONFIG_JZ4730) || defined(CONFIG_JZ5730) || defined(CONFIG_FPGA)
30 #if defined(CONFIG_JZ4730)
31 #include <asm/jz4730.h>
33 #if defined(CONFIG_JZ4740)
34 #include <asm/jz4740.h>
36 #if defined(CONFIG_JZ4750)
37 #include <asm/jz4750.h>
39 #if defined(CONFIG_JZ5730)
40 #include <asm/jz5730.h>
47 /* Tx and Rx Descriptor */
55 #define NUM_RX_DESCS 16
56 #define NUM_TX_DESCS 4
58 static eth_desc_t rx_desc
[NUM_RX_DESCS
];
59 static eth_desc_t tx_desc
[NUM_TX_DESCS
];
64 static u32 full_duplex
, phy_mode
;
66 static inline void reset_eth(void)
70 jz_writel(ETH_BMR
, jz_readl(ETH_BMR
) | BMR_SWR
);
72 for (i
= 0; i
< MAX_WAIT
; i
++) {
73 if(!(jz_readl(ETH_BMR
) & BMR_SWR
))
79 printf("Reset eth timeout\n");
82 static inline void enable_eth(void)
84 jz_writel(ETH_OMR
, jz_readl(ETH_OMR
) | OMR_ST
| OMR_SR
);
87 static inline void disable_eth(void)
89 jz_writel(ETH_OMR
, jz_readl(ETH_OMR
) & ~(OMR_ST
| OMR_SR
));
92 #define MII_CMD_ADDR(id, offset) (((id) << 11) | ((offset) << 6))
93 #define MII_CMD_READ(id, offset) (MII_CMD_ADDR(id, offset))
94 #define MII_CMD_WRITE(id, offset) (MII_CMD_ADDR(id, offset) | 0x2)
96 static u32
mii_read(int phy_id
, int offset
)
99 u32 mii_cmd
= MII_CMD_READ(phy_id
, offset
);
101 jz_writel(ETH_MIAR
, mii_cmd
);
103 /* wait for completion */
104 for (i
= 0; i
< MAX_WAIT
; i
++) {
105 if (!(jz_readl(ETH_MIAR
) & 0x1))
111 printf("MII wait timeout\n");
115 return jz_readl(ETH_MIDR
) & 0x0000ffff;
118 static int autonet_complete(int phy_id
)
122 for (i
= 0; i
< MAX_WAIT
; i
++) {
123 if (mii_read(phy_id
, MII_SR
) & 0x0020)
124 break; //auto negotiation completed
129 return -1; //auto negotiation error
134 static int search_phy(int phy_id
)
137 r
= mii_read(phy_id
, 1);
138 if (r
!=0 && r
!=0xffff)
143 static void config_phy(int phy_id
)
149 mii_reg5
= mii_read(phy_id
, MII_ANLPA
);
151 if (mii_reg5
!= 0xffff) {
152 mii_reg5
= mii_read(phy_id
, MII_ANLPA
);
153 if ((mii_reg5
& 0x0100) || (mii_reg5
& 0x01C0) == 0x0040)
156 phy_mode
= mii_reg5
>> 5;
158 printf("ETH: setting %s %s-duplex based on MII tranceiver #%d\n",
159 (phy_mode
& MII_ANLPA_100M
) ? "100Mbps" : "10Mbps",
160 full_duplex
? "full" : "half", phy_id
);
164 static void config_mac(void)
168 /* Set MAC address */
169 #define ea eth_get_dev()->enetaddr
170 jz_writel(ETH_MALR
, (ea
[3] << 24) | (ea
[2] << 16) | (ea
[1] << 8) | ea
[0]);
171 jz_writel(ETH_MAHR
, (ea
[5] << 8) | ea
[4]);
173 jz_writel(ETH_HTLR
, 0);
174 jz_writel(ETH_HTHR
, 0);
176 /* Assert the MCR_PS bit in CSR */
177 if (phy_mode
& MII_ANLPA_100M
)
180 omr
= OMR_TTM
| OMR_SF
;
182 mcr
= MCR_TE
| MCR_RE
| MCR_DBF
| MCR_LCC
;
187 /* Set the Operation Mode (OMR) and Mac Control (MCR) registers */
188 jz_writel(ETH_OMR
, omr
);
189 jz_writel(ETH_MCR
, mcr
);
191 /* Set the Programmable Burst Length (BMR.PBL, value 1 or 4 is validate) */
192 jz_writel(ETH_BMR
, DMA_BURST
<< 8);
195 jz_readl(ETH_MFCR
); // missed frams counter
198 /*---------------------------------------------------------------------------
199 * ETH interface routines
200 *--------------------------------------------------------------------------*/
202 static int jz_send(struct eth_device
* dev
, volatile void *packet
, int length
)
204 volatile eth_desc_t
*desc
=
205 (volatile eth_desc_t
*)((unsigned int)(tx_desc
+ next_tx
) | 0xa0000000);
208 /* tx fifo should always be idle */
209 desc
->addr
= virt_to_phys(packet
);
210 desc
->ctrl
|= TD_LS
| TD_FS
| length
;
211 desc
->status
= T_OWN
;
217 jz_writel(ETH_TPDR
, 1);
220 while (desc
->status
& T_OWN
) {
222 printf("ETH TX timeout\n");
229 /* Clear done bits */
230 jz_writel(ETH_SR
, DMA_TX_DEFAULT
);
234 desc
->ctrl
&= ~(TD_LS
| TD_FS
);
237 if (next_tx
>= NUM_TX_DESCS
){
241 return (desc
->status
);
244 static int jz_recv(struct eth_device
* dev
)
246 volatile eth_desc_t
*desc
;
251 desc
= (volatile eth_desc_t
*)((unsigned int)(rx_desc
+ next_rx
) | 0xa0000000);
253 status
= desc
->status
;
255 if (status
& R_OWN
) {
256 /* Nothing has been received */
260 length
= ((status
& RD_FL
) >> 16); /* with 4-byte CRC value */
262 if (status
& RD_ES
) {
263 printf("ETH RX error 0x%x\n", status
);
266 /* Pass the packet up to the protocol layers. */
267 NetReceive(NetRxPackets
[next_rx
], length
- 4);
270 /* Clear done bits */
271 jz_writel(ETH_SR
, DMA_RX_DEFAULT
);
273 desc
->status
= R_OWN
;
279 if (next_rx
>= NUM_RX_DESCS
) {
284 return(0); /* Does anyone use this? */
287 static int jz_init(struct eth_device
* dev
, bd_t
* bd
)
291 /* Reset ethernet unit */
294 /* Disable interrupts: we don't use ethernet interrupts */
295 jz_writel(ETH_IER
, 0);
304 printf("Can't locate any PHY\n");
306 /* Start Auto Negotiation of PHY 0 and check it */
307 if (autonet_complete(phyid
))
308 printf("ETH Auto-Negotiation failed\n");
316 /* Setup the Rx&Tx descriptors */
317 for (i
= 0; i
< NUM_RX_DESCS
; i
++) {
318 rx_desc
[i
].status
= R_OWN
;
319 rx_desc
[i
].ctrl
= PKTSIZE_ALIGN
| RD_RCH
;
320 rx_desc
[i
].addr
= virt_to_phys(NetRxPackets
[i
]);
321 rx_desc
[i
].next
= virt_to_phys(rx_desc
+ i
+ 1);
323 rx_desc
[NUM_RX_DESCS
- 1].next
= virt_to_phys(rx_desc
); // The last links to the first
324 rx_desc
[NUM_RX_DESCS
- 1].ctrl
|= RD_RER
; // Set the Receive End Of Ring flag
326 for (i
= 0; i
< NUM_TX_DESCS
; i
++) {
327 tx_desc
[i
].status
= 0;
328 tx_desc
[i
].ctrl
= TD_TCH
;
330 tx_desc
[i
].next
= virt_to_phys(tx_desc
+ i
+ 1);
332 tx_desc
[NUM_TX_DESCS
- 1].next
= virt_to_phys(tx_desc
); // The last links to the first
333 tx_desc
[NUM_TX_DESCS
- 1].ctrl
|= TD_TER
; // Set the Transmit End Of Ring flag
337 jz_writel(ETH_RAR
, virt_to_phys(rx_desc
));
338 jz_writel(ETH_TAR
, virt_to_phys(tx_desc
));
340 next_rx
= next_tx
= 0;
348 static void jz_halt(struct eth_device
*dev
)
353 int jz_enet_initialize(bd_t
*bis
)
355 struct eth_device
*dev
;
357 dev
= (struct eth_device
*) malloc(sizeof *dev
);
358 memset(dev
, 0, sizeof *dev
);
360 sprintf(dev
->name
, "JZ ETHERNET");
373 #endif /* CONFIG_JZ4730 || CONFIG_JZ5730 */