change console=tty0 to enable linux framebuffer console
[jz_uboot.git] / cpu / mips / jz_eth.c
blob7576461cdffee93abf82bd8ab68924cb6f199d65
1 /* Jz ethernet support
3 * Copyright (c) 2005
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,
19 * MA 02111-1307 USA
21 #include <config.h>
23 #if defined(CONFIG_JZ4730) || defined(CONFIG_JZ5730) || defined(CONFIG_FPGA)
25 #include <common.h>
26 #include <malloc.h>
27 #include <net.h>
28 #include <command.h>
29 #include <asm/io.h>
30 #if defined(CONFIG_JZ4730)
31 #include <asm/jz4730.h>
32 #endif
33 #if defined(CONFIG_JZ4740)
34 #include <asm/jz4740.h>
35 #endif
36 #if defined(CONFIG_JZ4750)
37 #include <asm/jz4750.h>
38 #endif
39 #if defined(CONFIG_JZ5730)
40 #include <asm/jz5730.h>
41 #endif
43 #include "jz_eth.h"
45 #define MAX_WAIT 1000
47 /* Tx and Rx Descriptor */
48 typedef struct {
49 u32 status;
50 u32 ctrl;
51 u32 addr;
52 u32 next;
53 } eth_desc_t;
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];
61 static int next_rx;
62 static int next_tx;
64 static u32 full_duplex, phy_mode;
66 static inline void reset_eth(void)
68 int i;
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))
74 break;
75 udelay(1);
78 if (i == MAX_WAIT)
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)
98 int i;
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))
106 break;
107 udelay(1);
110 if (i == MAX_WAIT) {
111 printf("MII wait timeout\n");
112 return 0;
115 return jz_readl(ETH_MIDR) & 0x0000ffff;
118 static int autonet_complete(int phy_id)
120 int i;
122 for (i = 0; i < MAX_WAIT; i++) {
123 if (mii_read(phy_id, MII_SR) & 0x0020)
124 break; //auto negotiation completed
125 udelay(500);
128 if (i == MAX_WAIT)
129 return -1; //auto negotiation error
130 else
131 return 0;
134 static int search_phy(int phy_id)
136 unsigned int r;
137 r = mii_read(phy_id, 1);
138 if (r!=0 && r!=0xffff)
139 return 1;
140 return 0;
143 static void config_phy(int phy_id)
145 u32 mii_reg5;
147 full_duplex = 0;
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)
154 full_duplex = 1;
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)
166 u32 omr, mcr;
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)
178 omr = OMR_SF;
179 else
180 omr = OMR_TTM | OMR_SF;
182 mcr = MCR_TE | MCR_RE | MCR_DBF | MCR_LCC;
184 if (full_duplex)
185 mcr |= MCR_FDX;
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);
194 /* Reset csr8 */
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);
206 int i;
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;
213 jz_flush_dcache();
214 jz_sync();
216 /* Start the tx */
217 jz_writel(ETH_TPDR, 1);
219 i = 0;
220 while (desc->status & T_OWN) {
221 if(i > MAX_WAIT) {
222 printf("ETH TX timeout\n");
223 break;
225 udelay(1);
226 i++;
229 /* Clear done bits */
230 jz_writel(ETH_SR, DMA_TX_DEFAULT);
232 desc->status = 0;
233 desc->addr = 0;
234 desc->ctrl &= ~(TD_LS | TD_FS);
236 next_tx++;
237 if (next_tx >= NUM_TX_DESCS){
238 next_tx=0;
241 return (desc->status);
244 static int jz_recv(struct eth_device* dev)
246 volatile eth_desc_t *desc;
247 int length;
248 u32 status;
250 for(;;) {
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 */
257 return(-1);
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);
265 else {
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;
275 jz_flush_dcache();
276 jz_sync();
278 next_rx++;
279 if (next_rx >= NUM_RX_DESCS) {
280 next_rx = 0;
282 } /* for */
284 return(0); /* Does anyone use this? */
287 static int jz_init(struct eth_device* dev, bd_t * bd)
289 int i, phyid = -1;
291 /* Reset ethernet unit */
292 reset_eth();
294 /* Disable interrupts: we don't use ethernet interrupts */
295 jz_writel(ETH_IER, 0);
297 for (i=0;i<32;i++)
298 if (search_phy(i)) {
299 phyid = i;
300 break;
303 if (phyid == -1)
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");
310 /* Configure PHY */
311 config_phy(phyid);
313 /* Configure MAC */
314 config_mac();
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;
329 tx_desc[i].addr = 0;
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
335 jz_flush_dcache();
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;
342 /* Enable ETH */
343 enable_eth();
345 return (1);
348 static void jz_halt(struct eth_device *dev)
350 disable_eth();
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");
361 dev->iobase = 0;
362 dev->priv = 0;
363 dev->init = jz_init;
364 dev->halt = jz_halt;
365 dev->send = jz_send;
366 dev->recv = jz_recv;
368 eth_register(dev);
370 return 1;
373 #endif /* CONFIG_JZ4730 || CONFIG_JZ5730 */