xref: /rk3399_rockchip-uboot/drivers/net/uli526x.c (revision 2439e4bfa111babf4bc07ba20efbf3e36036813e)
1*2439e4bfSJean-Christophe PLAGNIOL-VILLARD /*
2*2439e4bfSJean-Christophe PLAGNIOL-VILLARD  * Copyright (C) 2007 Freescale Semiconductor, Inc. All rights reserved.
3*2439e4bfSJean-Christophe PLAGNIOL-VILLARD  *
4*2439e4bfSJean-Christophe PLAGNIOL-VILLARD  * Author: Roy Zang <tie-fei.zang@freescale.com>, Sep, 2007
5*2439e4bfSJean-Christophe PLAGNIOL-VILLARD  *
6*2439e4bfSJean-Christophe PLAGNIOL-VILLARD  * Description:
7*2439e4bfSJean-Christophe PLAGNIOL-VILLARD  * ULI 526x Ethernet port driver.
8*2439e4bfSJean-Christophe PLAGNIOL-VILLARD  * Based on the Linux driver: drivers/net/tulip/uli526x.c
9*2439e4bfSJean-Christophe PLAGNIOL-VILLARD  *
10*2439e4bfSJean-Christophe PLAGNIOL-VILLARD  * This is free software; you can redistribute it and/or modify
11*2439e4bfSJean-Christophe PLAGNIOL-VILLARD  * it under the terms of  the GNU General  Public License as published by
12*2439e4bfSJean-Christophe PLAGNIOL-VILLARD  * the Free Software Foundation;  either version 2 of the  License, or
13*2439e4bfSJean-Christophe PLAGNIOL-VILLARD  * (at your option) any later version.
14*2439e4bfSJean-Christophe PLAGNIOL-VILLARD  */
15*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 
16*2439e4bfSJean-Christophe PLAGNIOL-VILLARD #include <common.h>
17*2439e4bfSJean-Christophe PLAGNIOL-VILLARD #include <malloc.h>
18*2439e4bfSJean-Christophe PLAGNIOL-VILLARD #include <net.h>
19*2439e4bfSJean-Christophe PLAGNIOL-VILLARD #include <asm/io.h>
20*2439e4bfSJean-Christophe PLAGNIOL-VILLARD #include <pci.h>
21*2439e4bfSJean-Christophe PLAGNIOL-VILLARD #include <miiphy.h>
22*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 
23*2439e4bfSJean-Christophe PLAGNIOL-VILLARD /* some kernel function compatible define */
24*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 
25*2439e4bfSJean-Christophe PLAGNIOL-VILLARD #if defined(CONFIG_CMD_NET) && defined(CONFIG_NET_MULTI) && \
26*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	defined(CONFIG_ULI526X)
27*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 
28*2439e4bfSJean-Christophe PLAGNIOL-VILLARD #undef DEBUG
29*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 
30*2439e4bfSJean-Christophe PLAGNIOL-VILLARD /* Board/System/Debug information/definition */
31*2439e4bfSJean-Christophe PLAGNIOL-VILLARD #define ULI_VENDOR_ID		0x10B9
32*2439e4bfSJean-Christophe PLAGNIOL-VILLARD #define ULI5261_DEVICE_ID	0x5261
33*2439e4bfSJean-Christophe PLAGNIOL-VILLARD #define ULI5263_DEVICE_ID	0x5263
34*2439e4bfSJean-Christophe PLAGNIOL-VILLARD /* ULi M5261 ID*/
35*2439e4bfSJean-Christophe PLAGNIOL-VILLARD #define PCI_ULI5261_ID		ULI5261_DEVICE_ID << 16 | ULI_VENDOR_ID
36*2439e4bfSJean-Christophe PLAGNIOL-VILLARD /* ULi M5263 ID*/
37*2439e4bfSJean-Christophe PLAGNIOL-VILLARD #define PCI_ULI5263_ID		ULI5263_DEVICE_ID << 16 | ULI_VENDOR_ID
38*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 
39*2439e4bfSJean-Christophe PLAGNIOL-VILLARD #define ULI526X_IO_SIZE	0x100
40*2439e4bfSJean-Christophe PLAGNIOL-VILLARD #define TX_DESC_CNT	0x10		/* Allocated Tx descriptors */
41*2439e4bfSJean-Christophe PLAGNIOL-VILLARD #define RX_DESC_CNT	PKTBUFSRX	/* Allocated Rx descriptors */
42*2439e4bfSJean-Christophe PLAGNIOL-VILLARD #define TX_FREE_DESC_CNT	(TX_DESC_CNT - 2) /* Max TX packet count */
43*2439e4bfSJean-Christophe PLAGNIOL-VILLARD #define TX_WAKE_DESC_CNT	(TX_DESC_CNT - 3) /* TX wakeup count */
44*2439e4bfSJean-Christophe PLAGNIOL-VILLARD #define DESC_ALL_CNT		(TX_DESC_CNT + RX_DESC_CNT)
45*2439e4bfSJean-Christophe PLAGNIOL-VILLARD #define TX_BUF_ALLOC		0x300
46*2439e4bfSJean-Christophe PLAGNIOL-VILLARD #define RX_ALLOC_SIZE		PKTSIZE
47*2439e4bfSJean-Christophe PLAGNIOL-VILLARD #define ULI526X_RESET		1
48*2439e4bfSJean-Christophe PLAGNIOL-VILLARD #define CR0_DEFAULT		0
49*2439e4bfSJean-Christophe PLAGNIOL-VILLARD #define CR6_DEFAULT		0x22200000
50*2439e4bfSJean-Christophe PLAGNIOL-VILLARD #define CR7_DEFAULT		0x180c1
51*2439e4bfSJean-Christophe PLAGNIOL-VILLARD #define CR15_DEFAULT		0x06		/* TxJabber RxWatchdog */
52*2439e4bfSJean-Christophe PLAGNIOL-VILLARD #define TDES0_ERR_MASK		0x4302		/* TXJT, LC, EC, FUE */
53*2439e4bfSJean-Christophe PLAGNIOL-VILLARD #define MAX_PACKET_SIZE		1514
54*2439e4bfSJean-Christophe PLAGNIOL-VILLARD #define ULI5261_MAX_MULTICAST	14
55*2439e4bfSJean-Christophe PLAGNIOL-VILLARD #define RX_COPY_SIZE		100
56*2439e4bfSJean-Christophe PLAGNIOL-VILLARD #define MAX_CHECK_PACKET	0x8000
57*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 
58*2439e4bfSJean-Christophe PLAGNIOL-VILLARD #define ULI526X_10MHF		0
59*2439e4bfSJean-Christophe PLAGNIOL-VILLARD #define ULI526X_100MHF		1
60*2439e4bfSJean-Christophe PLAGNIOL-VILLARD #define ULI526X_10MFD		4
61*2439e4bfSJean-Christophe PLAGNIOL-VILLARD #define ULI526X_100MFD		5
62*2439e4bfSJean-Christophe PLAGNIOL-VILLARD #define ULI526X_AUTO		8
63*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 
64*2439e4bfSJean-Christophe PLAGNIOL-VILLARD #define ULI526X_TXTH_72		0x400000	/* TX TH 72 byte */
65*2439e4bfSJean-Christophe PLAGNIOL-VILLARD #define ULI526X_TXTH_96		0x404000	/* TX TH 96 byte */
66*2439e4bfSJean-Christophe PLAGNIOL-VILLARD #define ULI526X_TXTH_128	0x0000		/* TX TH 128 byte */
67*2439e4bfSJean-Christophe PLAGNIOL-VILLARD #define ULI526X_TXTH_256	0x4000		/* TX TH 256 byte */
68*2439e4bfSJean-Christophe PLAGNIOL-VILLARD #define ULI526X_TXTH_512	0x8000		/* TX TH 512 byte */
69*2439e4bfSJean-Christophe PLAGNIOL-VILLARD #define ULI526X_TXTH_1K		0xC000		/* TX TH 1K  byte */
70*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 
71*2439e4bfSJean-Christophe PLAGNIOL-VILLARD /* CR9 definition: SROM/MII */
72*2439e4bfSJean-Christophe PLAGNIOL-VILLARD #define CR9_SROM_READ		0x4800
73*2439e4bfSJean-Christophe PLAGNIOL-VILLARD #define CR9_SRCS		0x1
74*2439e4bfSJean-Christophe PLAGNIOL-VILLARD #define CR9_SRCLK		0x2
75*2439e4bfSJean-Christophe PLAGNIOL-VILLARD #define CR9_CRDOUT		0x8
76*2439e4bfSJean-Christophe PLAGNIOL-VILLARD #define SROM_DATA_0		0x0
77*2439e4bfSJean-Christophe PLAGNIOL-VILLARD #define SROM_DATA_1		0x4
78*2439e4bfSJean-Christophe PLAGNIOL-VILLARD #define PHY_DATA_1		0x20000
79*2439e4bfSJean-Christophe PLAGNIOL-VILLARD #define PHY_DATA_0		0x00000
80*2439e4bfSJean-Christophe PLAGNIOL-VILLARD #define MDCLKH			0x10000
81*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 
82*2439e4bfSJean-Christophe PLAGNIOL-VILLARD #define PHY_POWER_DOWN	0x800
83*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 
84*2439e4bfSJean-Christophe PLAGNIOL-VILLARD #define SROM_V41_CODE		0x14
85*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 
86*2439e4bfSJean-Christophe PLAGNIOL-VILLARD #define SROM_CLK_WRITE(data, ioaddr) do {			\
87*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	outl(data|CR9_SROM_READ|CR9_SRCS, ioaddr);		\
88*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	udelay(5);						\
89*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	outl(data|CR9_SROM_READ|CR9_SRCS|CR9_SRCLK, ioaddr);	\
90*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	udelay(5);						\
91*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	outl(data|CR9_SROM_READ|CR9_SRCS, ioaddr);		\
92*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	udelay(5);						\
93*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	} while (0)
94*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 
95*2439e4bfSJean-Christophe PLAGNIOL-VILLARD /* Structure/enum declaration */
96*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 
97*2439e4bfSJean-Christophe PLAGNIOL-VILLARD struct tx_desc {
98*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	u32 tdes0, tdes1, tdes2, tdes3; /* Data for the card */
99*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	char *tx_buf_ptr;		/* Data for us */
100*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	struct tx_desc *next_tx_desc;
101*2439e4bfSJean-Christophe PLAGNIOL-VILLARD };
102*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 
103*2439e4bfSJean-Christophe PLAGNIOL-VILLARD struct rx_desc {
104*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	u32 rdes0, rdes1, rdes2, rdes3;	/* Data for the card */
105*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	char *rx_buf_ptr;		/* Data for us */
106*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	struct rx_desc *next_rx_desc;
107*2439e4bfSJean-Christophe PLAGNIOL-VILLARD };
108*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 
109*2439e4bfSJean-Christophe PLAGNIOL-VILLARD struct uli526x_board_info {
110*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	u32 chip_id;	/* Chip vendor/Device ID */
111*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	pci_dev_t pdev;
112*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 
113*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	long ioaddr;			/* I/O base address */
114*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	u32 cr0_data;
115*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	u32 cr5_data;
116*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	u32 cr6_data;
117*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	u32 cr7_data;
118*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	u32 cr15_data;
119*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 
120*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	/* pointer for memory physical address */
121*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	dma_addr_t buf_pool_dma_ptr;	/* Tx buffer pool memory */
122*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	dma_addr_t buf_pool_dma_start;	/* Tx buffer pool align dword */
123*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	dma_addr_t desc_pool_dma_ptr;	/* descriptor pool memory */
124*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	dma_addr_t first_tx_desc_dma;
125*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	dma_addr_t first_rx_desc_dma;
126*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 
127*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	/* descriptor pointer */
128*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	unsigned char *buf_pool_ptr;	/* Tx buffer pool memory */
129*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	unsigned char *buf_pool_start;	/* Tx buffer pool align dword */
130*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	unsigned char *desc_pool_ptr;	/* descriptor pool memory */
131*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	struct tx_desc *first_tx_desc;
132*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	struct tx_desc *tx_insert_ptr;
133*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	struct tx_desc *tx_remove_ptr;
134*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	struct rx_desc *first_rx_desc;
135*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	struct rx_desc *rx_ready_ptr;	/* packet come pointer */
136*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	unsigned long tx_packet_cnt;	/* transmitted packet count */
137*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 
138*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	u16 PHY_reg4;			/* Saved Phyxcer register 4 value */
139*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 
140*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	u8 media_mode;			/* user specify media mode */
141*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	u8 op_mode;			/* real work dedia mode */
142*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	u8 phy_addr;
143*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 
144*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	/* NIC SROM data */
145*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	unsigned char srom[128];
146*2439e4bfSJean-Christophe PLAGNIOL-VILLARD };
147*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 
148*2439e4bfSJean-Christophe PLAGNIOL-VILLARD enum uli526x_offsets {
149*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	DCR0 = 0x00, DCR1 = 0x08, DCR2 = 0x10, DCR3 = 0x18, DCR4 = 0x20,
150*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	DCR5 = 0x28, DCR6 = 0x30, DCR7 = 0x38, DCR8 = 0x40, DCR9 = 0x48,
151*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	DCR10 = 0x50, DCR11 = 0x58, DCR12 = 0x60, DCR13 = 0x68, DCR14 = 0x70,
152*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	DCR15 = 0x78
153*2439e4bfSJean-Christophe PLAGNIOL-VILLARD };
154*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 
155*2439e4bfSJean-Christophe PLAGNIOL-VILLARD enum uli526x_CR6_bits {
156*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	CR6_RXSC = 0x2, CR6_PBF = 0x8, CR6_PM = 0x40, CR6_PAM = 0x80,
157*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	CR6_FDM = 0x200, CR6_TXSC = 0x2000, CR6_STI = 0x100000,
158*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	CR6_SFT = 0x200000, CR6_RXA = 0x40000000, CR6_NO_PURGE = 0x20000000
159*2439e4bfSJean-Christophe PLAGNIOL-VILLARD };
160*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 
161*2439e4bfSJean-Christophe PLAGNIOL-VILLARD /* Global variable declaration -- */
162*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 
163*2439e4bfSJean-Christophe PLAGNIOL-VILLARD static unsigned char uli526x_media_mode = ULI526X_AUTO;
164*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 
165*2439e4bfSJean-Christophe PLAGNIOL-VILLARD static struct tx_desc desc_pool_array[DESC_ALL_CNT + 0x20]
166*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	__attribute__ ((aligned(32)));
167*2439e4bfSJean-Christophe PLAGNIOL-VILLARD static char buf_pool[TX_BUF_ALLOC * TX_DESC_CNT + 4];
168*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 
169*2439e4bfSJean-Christophe PLAGNIOL-VILLARD /* For module input parameter */
170*2439e4bfSJean-Christophe PLAGNIOL-VILLARD static int mode = 8;
171*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 
172*2439e4bfSJean-Christophe PLAGNIOL-VILLARD /* function declaration -- */
173*2439e4bfSJean-Christophe PLAGNIOL-VILLARD static int uli526x_start_xmit(struct eth_device *dev,
174*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 				volatile void *packet, int length);
175*2439e4bfSJean-Christophe PLAGNIOL-VILLARD static const struct ethtool_ops netdev_ethtool_ops;
176*2439e4bfSJean-Christophe PLAGNIOL-VILLARD static u16 read_srom_word(long, int);
177*2439e4bfSJean-Christophe PLAGNIOL-VILLARD static void uli526x_descriptor_init(struct uli526x_board_info *, unsigned long);
178*2439e4bfSJean-Christophe PLAGNIOL-VILLARD static void allocate_rx_buffer(struct uli526x_board_info *);
179*2439e4bfSJean-Christophe PLAGNIOL-VILLARD static void update_cr6(u32, unsigned long);
180*2439e4bfSJean-Christophe PLAGNIOL-VILLARD static u16 phy_read(unsigned long, u8, u8, u32);
181*2439e4bfSJean-Christophe PLAGNIOL-VILLARD static u16 phy_readby_cr10(unsigned long, u8, u8);
182*2439e4bfSJean-Christophe PLAGNIOL-VILLARD static void phy_write(unsigned long, u8, u8, u16, u32);
183*2439e4bfSJean-Christophe PLAGNIOL-VILLARD static void phy_writeby_cr10(unsigned long, u8, u8, u16);
184*2439e4bfSJean-Christophe PLAGNIOL-VILLARD static void phy_write_1bit(unsigned long, u32, u32);
185*2439e4bfSJean-Christophe PLAGNIOL-VILLARD static u16 phy_read_1bit(unsigned long, u32);
186*2439e4bfSJean-Christophe PLAGNIOL-VILLARD static int uli526x_rx_packet(struct eth_device *);
187*2439e4bfSJean-Christophe PLAGNIOL-VILLARD static void uli526x_free_tx_pkt(struct eth_device *,
188*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 		struct uli526x_board_info *);
189*2439e4bfSJean-Christophe PLAGNIOL-VILLARD static void uli526x_reuse_buf(struct rx_desc *);
190*2439e4bfSJean-Christophe PLAGNIOL-VILLARD static void uli526x_init(struct eth_device *);
191*2439e4bfSJean-Christophe PLAGNIOL-VILLARD static void uli526x_set_phyxcer(struct uli526x_board_info *);
192*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 
193*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 
194*2439e4bfSJean-Christophe PLAGNIOL-VILLARD static int uli526x_init_one(struct eth_device *, bd_t *);
195*2439e4bfSJean-Christophe PLAGNIOL-VILLARD static void uli526x_disable(struct eth_device *);
196*2439e4bfSJean-Christophe PLAGNIOL-VILLARD static void set_mac_addr(struct eth_device *);
197*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 
198*2439e4bfSJean-Christophe PLAGNIOL-VILLARD static struct pci_device_id uli526x_pci_tbl[] = {
199*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	{ ULI_VENDOR_ID, ULI5261_DEVICE_ID}, /* 5261 device */
200*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	{ ULI_VENDOR_ID, ULI5263_DEVICE_ID}, /* 5263 device */
201*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	{}
202*2439e4bfSJean-Christophe PLAGNIOL-VILLARD };
203*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 
204*2439e4bfSJean-Christophe PLAGNIOL-VILLARD /* ULI526X network board routine */
205*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 
206*2439e4bfSJean-Christophe PLAGNIOL-VILLARD /*
207*2439e4bfSJean-Christophe PLAGNIOL-VILLARD  *	Search ULI526X board, register it
208*2439e4bfSJean-Christophe PLAGNIOL-VILLARD  */
209*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 
210*2439e4bfSJean-Christophe PLAGNIOL-VILLARD int uli526x_initialize(bd_t *bis)
211*2439e4bfSJean-Christophe PLAGNIOL-VILLARD {
212*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	pci_dev_t devno;
213*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	int card_number = 0;
214*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	struct eth_device *dev;
215*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	struct uli526x_board_info *db;	/* board information structure */
216*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 
217*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	u32 iobase;
218*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	int idx = 0;
219*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 
220*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	while (1) {
221*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 		/* Find PCI device */
222*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 		devno = pci_find_devices(uli526x_pci_tbl, idx++);
223*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 		if (devno < 0)
224*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 			break;
225*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 
226*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 		pci_read_config_dword(devno, PCI_BASE_ADDRESS_1, &iobase);
227*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 		iobase &= ~0xf;
228*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 
229*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 		dev = (struct eth_device *)malloc(sizeof *dev);
230*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 		sprintf(dev->name, "uli526x#%d\n", card_number);
231*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 		db = (struct uli526x_board_info *)
232*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 			malloc(sizeof(struct uli526x_board_info));
233*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 
234*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 		dev->priv = db;
235*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 		db->pdev = devno;
236*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 		dev->iobase = iobase;
237*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 
238*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 		dev->init = uli526x_init_one;
239*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 		dev->halt = uli526x_disable;
240*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 		dev->send = uli526x_start_xmit;
241*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 		dev->recv = uli526x_rx_packet;
242*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 
243*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 		/* init db */
244*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 		db->ioaddr = dev->iobase;
245*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 		/* get chip id */
246*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 
247*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 		pci_read_config_dword(devno, PCI_VENDOR_ID, &db->chip_id);
248*2439e4bfSJean-Christophe PLAGNIOL-VILLARD #ifdef DEBUG
249*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 		printf("uli526x: uli526x @0x%x\n", iobase);
250*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 		printf("uli526x: chip_id%x\n", db->chip_id);
251*2439e4bfSJean-Christophe PLAGNIOL-VILLARD #endif
252*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 		eth_register(dev);
253*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 		card_number++;
254*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 		pci_write_config_byte(devno, PCI_LATENCY_TIMER, 0x20);
255*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 		udelay(10 * 1000);
256*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	}
257*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	return card_number;
258*2439e4bfSJean-Christophe PLAGNIOL-VILLARD }
259*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 
260*2439e4bfSJean-Christophe PLAGNIOL-VILLARD static int uli526x_init_one(struct eth_device *dev, bd_t *bis)
261*2439e4bfSJean-Christophe PLAGNIOL-VILLARD {
262*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 
263*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	struct uli526x_board_info *db = dev->priv;
264*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	int i;
265*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 
266*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	switch (mode) {
267*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	case ULI526X_10MHF:
268*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	case ULI526X_100MHF:
269*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	case ULI526X_10MFD:
270*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	case ULI526X_100MFD:
271*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 		uli526x_media_mode = mode;
272*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 		break;
273*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	default:
274*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 		uli526x_media_mode = ULI526X_AUTO;
275*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 		break;
276*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	}
277*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 
278*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	/* Allocate Tx/Rx descriptor memory */
279*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	db->desc_pool_ptr = (uchar *)&desc_pool_array[0];
280*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	db->desc_pool_dma_ptr = (dma_addr_t)&desc_pool_array[0];
281*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	if (db->desc_pool_ptr == NULL)
282*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 		return 0;
283*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 
284*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	db->buf_pool_ptr = &buf_pool[0];
285*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	db->buf_pool_dma_ptr = (dma_addr_t)&buf_pool[0];
286*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	if (db->buf_pool_ptr == NULL)
287*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 		return 0;
288*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 
289*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	db->first_tx_desc = (struct tx_desc *) db->desc_pool_ptr;
290*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	db->first_tx_desc_dma = db->desc_pool_dma_ptr;
291*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 
292*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	db->buf_pool_start = db->buf_pool_ptr;
293*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	db->buf_pool_dma_start = db->buf_pool_dma_ptr;
294*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 
295*2439e4bfSJean-Christophe PLAGNIOL-VILLARD #ifdef DEBUG
296*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	printf("%s(): db->ioaddr= 0x%x\n",
297*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 		__FUNCTION__, db->ioaddr);
298*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	printf("%s(): media_mode= 0x%x\n",
299*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 		__FUNCTION__, uli526x_media_mode);
300*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	printf("%s(): db->desc_pool_ptr= 0x%x\n",
301*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 		__FUNCTION__, db->desc_pool_ptr);
302*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	printf("%s(): db->desc_pool_dma_ptr= 0x%x\n",
303*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 		__FUNCTION__, db->desc_pool_dma_ptr);
304*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	printf("%s(): db->buf_pool_ptr= 0x%x\n",
305*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 		__FUNCTION__, db->buf_pool_ptr);
306*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	printf("%s(): db->buf_pool_dma_ptr= 0x%x\n",
307*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 		__FUNCTION__, db->buf_pool_dma_ptr);
308*2439e4bfSJean-Christophe PLAGNIOL-VILLARD #endif
309*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 
310*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	/* read 64 word srom data */
311*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	for (i = 0; i < 64; i++)
312*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 		((u16 *) db->srom)[i] = cpu_to_le16(read_srom_word(db->ioaddr,
313*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 			i));
314*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 
315*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	/* Set Node address */
316*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	if (((u16 *) db->srom)[0] == 0xffff || ((u16 *) db->srom)[0] == 0)
317*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	/* SROM absent, so write MAC address to ID Table */
318*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 		set_mac_addr(dev);
319*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	else {		/*Exist SROM*/
320*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 		for (i = 0; i < 6; i++)
321*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 			dev->enetaddr[i] = db->srom[20 + i];
322*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	}
323*2439e4bfSJean-Christophe PLAGNIOL-VILLARD #ifdef DEBUG
324*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	for (i = 0; i < 6; i++)
325*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 		printf("%c%02x", i ? ':' : ' ', dev->enetaddr[i]);
326*2439e4bfSJean-Christophe PLAGNIOL-VILLARD #endif
327*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	db->PHY_reg4 = 0x1e0;
328*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 
329*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	/* system variable init */
330*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	db->cr6_data = CR6_DEFAULT ;
331*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	db->cr6_data |= ULI526X_TXTH_256;
332*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	db->cr0_data = CR0_DEFAULT;
333*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	uli526x_init(dev);
334*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	return 1;
335*2439e4bfSJean-Christophe PLAGNIOL-VILLARD }
336*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 
337*2439e4bfSJean-Christophe PLAGNIOL-VILLARD static void uli526x_disable(struct eth_device *dev)
338*2439e4bfSJean-Christophe PLAGNIOL-VILLARD {
339*2439e4bfSJean-Christophe PLAGNIOL-VILLARD #ifdef DEBUG
340*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	printf("uli526x_disable\n");
341*2439e4bfSJean-Christophe PLAGNIOL-VILLARD #endif
342*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	struct uli526x_board_info *db = dev->priv;
343*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 
344*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	if (!((inl(db->ioaddr + DCR12)) & 0x8)) {
345*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 		/* Reset & stop ULI526X board */
346*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 		outl(ULI526X_RESET, db->ioaddr + DCR0);
347*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 		udelay(5);
348*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 		phy_write(db->ioaddr, db->phy_addr, 0, 0x8000, db->chip_id);
349*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 
350*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 		/* reset the board */
351*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 		db->cr6_data &= ~(CR6_RXSC | CR6_TXSC);	/* Disable Tx/Rx */
352*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 		update_cr6(db->cr6_data, dev->iobase);
353*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 		outl(0, dev->iobase + DCR7);		/* Disable Interrupt */
354*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 		outl(inl(dev->iobase + DCR5), dev->iobase + DCR5);
355*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	}
356*2439e4bfSJean-Christophe PLAGNIOL-VILLARD }
357*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 
358*2439e4bfSJean-Christophe PLAGNIOL-VILLARD /*	Initialize ULI526X board
359*2439e4bfSJean-Christophe PLAGNIOL-VILLARD  *	Reset ULI526X board
360*2439e4bfSJean-Christophe PLAGNIOL-VILLARD  *	Initialize TX/Rx descriptor chain structure
361*2439e4bfSJean-Christophe PLAGNIOL-VILLARD  *	Send the set-up frame
362*2439e4bfSJean-Christophe PLAGNIOL-VILLARD  *	Enable Tx/Rx machine
363*2439e4bfSJean-Christophe PLAGNIOL-VILLARD  */
364*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 
365*2439e4bfSJean-Christophe PLAGNIOL-VILLARD static void uli526x_init(struct eth_device *dev)
366*2439e4bfSJean-Christophe PLAGNIOL-VILLARD {
367*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 
368*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	struct uli526x_board_info *db = dev->priv;
369*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	u8	phy_tmp;
370*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	u16	phy_value;
371*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	u16 phy_reg_reset;
372*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 
373*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	/* Reset M526x MAC controller */
374*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	outl(ULI526X_RESET, db->ioaddr + DCR0);	/* RESET MAC */
375*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	udelay(100);
376*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	outl(db->cr0_data, db->ioaddr + DCR0);
377*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	udelay(5);
378*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 
379*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	/* Phy addr : In some boards,M5261/M5263 phy address != 1 */
380*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	db->phy_addr = 1;
381*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	db->tx_packet_cnt = 0;
382*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	for (phy_tmp = 0; phy_tmp < 32; phy_tmp++) {
383*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 		/* peer add */
384*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 		phy_value = phy_read(db->ioaddr, phy_tmp, 3, db->chip_id);
385*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 		if (phy_value != 0xffff && phy_value != 0) {
386*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 			db->phy_addr = phy_tmp;
387*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 			break;
388*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 		}
389*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	}
390*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 
391*2439e4bfSJean-Christophe PLAGNIOL-VILLARD #ifdef DEBUG
392*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	printf("%s(): db->ioaddr= 0x%x\n", __FUNCTION__, db->ioaddr);
393*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	printf("%s(): db->phy_addr= 0x%x\n", __FUNCTION__, db->phy_addr);
394*2439e4bfSJean-Christophe PLAGNIOL-VILLARD #endif
395*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	if (phy_tmp == 32)
396*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 		printf("Can not find the phy address!!!");
397*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 
398*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	/* Parser SROM and media mode */
399*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	db->media_mode = uli526x_media_mode;
400*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 
401*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	if (!(inl(db->ioaddr + DCR12) & 0x8)) {
402*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 		/* Phyxcer capability setting */
403*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 		phy_reg_reset = phy_read(db->ioaddr,
404*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 			db->phy_addr, 0, db->chip_id);
405*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 		phy_reg_reset = (phy_reg_reset | 0x8000);
406*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 		phy_write(db->ioaddr, db->phy_addr, 0,
407*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 			phy_reg_reset, db->chip_id);
408*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 		udelay(500);
409*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 
410*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 		/* Process Phyxcer Media Mode */
411*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 		uli526x_set_phyxcer(db);
412*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	}
413*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	/* Media Mode Process */
414*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	if (!(db->media_mode & ULI526X_AUTO))
415*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 		db->op_mode = db->media_mode; 	/* Force Mode */
416*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 
417*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	/* Initialize Transmit/Receive decriptor and CR3/4 */
418*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	uli526x_descriptor_init(db, db->ioaddr);
419*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 
420*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	/* Init CR6 to program M526X operation */
421*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	update_cr6(db->cr6_data, db->ioaddr);
422*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 
423*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	/* Init CR7, interrupt active bit */
424*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	db->cr7_data = CR7_DEFAULT;
425*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	outl(db->cr7_data, db->ioaddr + DCR7);
426*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 
427*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	/* Init CR15, Tx jabber and Rx watchdog timer */
428*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	outl(db->cr15_data, db->ioaddr + DCR15);
429*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 
430*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	/* Enable ULI526X Tx/Rx function */
431*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	db->cr6_data |= CR6_RXSC | CR6_TXSC;
432*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	update_cr6(db->cr6_data, db->ioaddr);
433*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	while (!(inl(db->ioaddr + DCR12) & 0x8))
434*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 		udelay(10);
435*2439e4bfSJean-Christophe PLAGNIOL-VILLARD }
436*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 
437*2439e4bfSJean-Christophe PLAGNIOL-VILLARD /*
438*2439e4bfSJean-Christophe PLAGNIOL-VILLARD  *	Hardware start transmission.
439*2439e4bfSJean-Christophe PLAGNIOL-VILLARD  *	Send a packet to media from the upper layer.
440*2439e4bfSJean-Christophe PLAGNIOL-VILLARD  */
441*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 
442*2439e4bfSJean-Christophe PLAGNIOL-VILLARD static int uli526x_start_xmit(struct eth_device *dev,
443*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 				volatile void *packet, int length)
444*2439e4bfSJean-Christophe PLAGNIOL-VILLARD {
445*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	struct uli526x_board_info *db = dev->priv;
446*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	struct tx_desc *txptr;
447*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	unsigned int len = length;
448*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	/* Too large packet check */
449*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	if (len > MAX_PACKET_SIZE) {
450*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 		printf(": big packet = %d\n", len);
451*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 		return 0;
452*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	}
453*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 
454*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	/* No Tx resource check, it never happen nromally */
455*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	if (db->tx_packet_cnt >= TX_FREE_DESC_CNT) {
456*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 		printf("No Tx resource %ld\n", db->tx_packet_cnt);
457*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 		return 0;
458*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	}
459*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 
460*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	/* Disable NIC interrupt */
461*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	outl(0, dev->iobase + DCR7);
462*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 
463*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	/* transmit this packet */
464*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	txptr = db->tx_insert_ptr;
465*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	memcpy((char *)txptr->tx_buf_ptr, (char *)packet, (int)length);
466*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	txptr->tdes1 = cpu_to_le32(0xe1000000 | length);
467*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 
468*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	/* Point to next transmit free descriptor */
469*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	db->tx_insert_ptr = txptr->next_tx_desc;
470*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 
471*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	/* Transmit Packet Process */
472*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	if ((db->tx_packet_cnt < TX_DESC_CNT)) {
473*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 		txptr->tdes0 = cpu_to_le32(0x80000000);	/* Set owner bit */
474*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 		db->tx_packet_cnt++;			/* Ready to send */
475*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 		outl(0x1, dev->iobase + DCR1);	/* Issue Tx polling */
476*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	}
477*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 
478*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	/* Got ULI526X status */
479*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	db->cr5_data = inl(db->ioaddr + DCR5);
480*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	outl(db->cr5_data, db->ioaddr + DCR5);
481*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 
482*2439e4bfSJean-Christophe PLAGNIOL-VILLARD #ifdef TX_DEBUG
483*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	printf("%s(): length = 0x%x\n", __FUNCTION__, length);
484*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	printf("%s(): cr5_data=%x\n", __FUNCTION__, db->cr5_data);
485*2439e4bfSJean-Christophe PLAGNIOL-VILLARD #endif
486*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 
487*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	outl(db->cr7_data, dev->iobase + DCR7);
488*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	uli526x_free_tx_pkt(dev, db);
489*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 
490*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	return length;
491*2439e4bfSJean-Christophe PLAGNIOL-VILLARD }
492*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 
493*2439e4bfSJean-Christophe PLAGNIOL-VILLARD /*
494*2439e4bfSJean-Christophe PLAGNIOL-VILLARD  *	Free TX resource after TX complete
495*2439e4bfSJean-Christophe PLAGNIOL-VILLARD  */
496*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 
497*2439e4bfSJean-Christophe PLAGNIOL-VILLARD static void uli526x_free_tx_pkt(struct eth_device *dev,
498*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	struct uli526x_board_info *db)
499*2439e4bfSJean-Christophe PLAGNIOL-VILLARD {
500*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	struct tx_desc *txptr;
501*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	u32 tdes0;
502*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 
503*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	txptr = db->tx_remove_ptr;
504*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	while (db->tx_packet_cnt) {
505*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 		tdes0 = le32_to_cpu(txptr->tdes0);
506*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 		/* printf(DRV_NAME ": tdes0=%x\n", tdes0); */
507*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 		if (tdes0 & 0x80000000)
508*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 			break;
509*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 
510*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 		/* A packet sent completed */
511*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 		db->tx_packet_cnt--;
512*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 
513*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 		if (tdes0 != 0x7fffffff) {
514*2439e4bfSJean-Christophe PLAGNIOL-VILLARD #ifdef TX_DEBUG
515*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 			printf("%s()tdes0=%x\n", __FUNCTION__, tdes0);
516*2439e4bfSJean-Christophe PLAGNIOL-VILLARD #endif
517*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 			if (tdes0 & TDES0_ERR_MASK) {
518*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 				if (tdes0 & 0x0002) {	/* UnderRun */
519*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 					if (!(db->cr6_data & CR6_SFT)) {
520*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 						db->cr6_data = db->cr6_data |
521*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 							CR6_SFT;
522*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 						update_cr6(db->cr6_data,
523*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 							db->ioaddr);
524*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 					}
525*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 				}
526*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 			}
527*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 		}
528*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 
529*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 		txptr = txptr->next_tx_desc;
530*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	}/* End of while */
531*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 
532*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	/* Update TX remove pointer to next */
533*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	db->tx_remove_ptr = txptr;
534*2439e4bfSJean-Christophe PLAGNIOL-VILLARD }
535*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 
536*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 
537*2439e4bfSJean-Christophe PLAGNIOL-VILLARD /*
538*2439e4bfSJean-Christophe PLAGNIOL-VILLARD  *	Receive the come packet and pass to upper layer
539*2439e4bfSJean-Christophe PLAGNIOL-VILLARD  */
540*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 
541*2439e4bfSJean-Christophe PLAGNIOL-VILLARD static int uli526x_rx_packet(struct eth_device *dev)
542*2439e4bfSJean-Christophe PLAGNIOL-VILLARD {
543*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	struct uli526x_board_info *db = dev->priv;
544*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	struct rx_desc *rxptr;
545*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	int rxlen = 0;
546*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	u32 rdes0;
547*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 
548*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	rxptr = db->rx_ready_ptr;
549*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 
550*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	rdes0 = le32_to_cpu(rxptr->rdes0);
551*2439e4bfSJean-Christophe PLAGNIOL-VILLARD #ifdef RX_DEBUG
552*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	printf("%s(): rxptr->rdes0=%x:%x\n", __FUNCTION__, rxptr->rdes0);
553*2439e4bfSJean-Christophe PLAGNIOL-VILLARD #endif
554*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	if (!(rdes0 & 0x80000000)) {	/* packet owner check */
555*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 		if ((rdes0 & 0x300) != 0x300) {
556*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 			/* A packet without First/Last flag */
557*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 			/* reuse this buf */
558*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 			printf("A packet without First/Last flag");
559*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 			uli526x_reuse_buf(rxptr);
560*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 		} else {
561*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 			/* A packet with First/Last flag */
562*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 			rxlen = ((rdes0 >> 16) & 0x3fff) - 4;
563*2439e4bfSJean-Christophe PLAGNIOL-VILLARD #ifdef RX_DEBUG
564*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 			printf("%s(): rxlen =%x\n", __FUNCTION__, rxlen);
565*2439e4bfSJean-Christophe PLAGNIOL-VILLARD #endif
566*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 			/* error summary bit check */
567*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 			if (rdes0 & 0x8000) {
568*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 				/* This is a error packet */
569*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 				printf("Eroor: rdes0: %lx\n", rdes0);
570*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 			}
571*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 
572*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 			if (!(rdes0 & 0x8000) ||
573*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 				((db->cr6_data & CR6_PM) && (rxlen > 6))) {
574*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 
575*2439e4bfSJean-Christophe PLAGNIOL-VILLARD #ifdef RX_DEBUG
576*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 				printf("%s(): rx_skb_ptr =%x\n",
577*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 					__FUNCTION__, rxptr->rx_buf_ptr);
578*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 				printf("%s(): rxlen =%x\n",
579*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 					__FUNCTION__, rxlen);
580*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 
581*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 				printf("%s(): buf addr =%x\n",
582*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 					__FUNCTION__, rxptr->rx_buf_ptr);
583*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 				printf("%s(): rxlen =%x\n",
584*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 					__FUNCTION__, rxlen);
585*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 				int i;
586*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 				for (i = 0; i < 0x20; i++)
587*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 					printf("%s(): data[%x] =%x\n",
588*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 					__FUNCTION__, i, rxptr->rx_buf_ptr[i]);
589*2439e4bfSJean-Christophe PLAGNIOL-VILLARD #endif
590*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 
591*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 				NetReceive(rxptr->rx_buf_ptr, rxlen);
592*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 				uli526x_reuse_buf(rxptr);
593*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 
594*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 			} else {
595*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 				/* Reuse SKB buffer when the packet is error */
596*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 				printf("Reuse buffer, rdes0");
597*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 				uli526x_reuse_buf(rxptr);
598*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 			}
599*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 		}
600*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 
601*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 		rxptr = rxptr->next_rx_desc;
602*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	}
603*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 
604*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	db->rx_ready_ptr = rxptr;
605*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	return rxlen;
606*2439e4bfSJean-Christophe PLAGNIOL-VILLARD }
607*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 
608*2439e4bfSJean-Christophe PLAGNIOL-VILLARD /*
609*2439e4bfSJean-Christophe PLAGNIOL-VILLARD  *	Reuse the RX buffer
610*2439e4bfSJean-Christophe PLAGNIOL-VILLARD  */
611*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 
612*2439e4bfSJean-Christophe PLAGNIOL-VILLARD static void uli526x_reuse_buf(struct rx_desc *rxptr)
613*2439e4bfSJean-Christophe PLAGNIOL-VILLARD {
614*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 
615*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	if (!(rxptr->rdes0 & cpu_to_le32(0x80000000)))
616*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 		rxptr->rdes0 = cpu_to_le32(0x80000000);
617*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	else
618*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 		printf("Buffer reuse method error");
619*2439e4bfSJean-Christophe PLAGNIOL-VILLARD }
620*2439e4bfSJean-Christophe PLAGNIOL-VILLARD /*
621*2439e4bfSJean-Christophe PLAGNIOL-VILLARD  *	Initialize transmit/Receive descriptor
622*2439e4bfSJean-Christophe PLAGNIOL-VILLARD  *	Using Chain structure, and allocate Tx/Rx buffer
623*2439e4bfSJean-Christophe PLAGNIOL-VILLARD  */
624*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 
625*2439e4bfSJean-Christophe PLAGNIOL-VILLARD static void uli526x_descriptor_init(struct uli526x_board_info *db,
626*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	unsigned long ioaddr)
627*2439e4bfSJean-Christophe PLAGNIOL-VILLARD {
628*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	struct tx_desc *tmp_tx;
629*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	struct rx_desc *tmp_rx;
630*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	unsigned char *tmp_buf;
631*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	dma_addr_t tmp_tx_dma, tmp_rx_dma;
632*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	dma_addr_t tmp_buf_dma;
633*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	int i;
634*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	/* tx descriptor start pointer */
635*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	db->tx_insert_ptr = db->first_tx_desc;
636*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	db->tx_remove_ptr = db->first_tx_desc;
637*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 
638*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	outl(db->first_tx_desc_dma, ioaddr + DCR4);     /* TX DESC address */
639*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 
640*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	/* rx descriptor start pointer */
641*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	db->first_rx_desc = (void *)db->first_tx_desc +
642*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 		sizeof(struct tx_desc) * TX_DESC_CNT;
643*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	db->first_rx_desc_dma =  db->first_tx_desc_dma +
644*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 		sizeof(struct tx_desc) * TX_DESC_CNT;
645*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	db->rx_ready_ptr = db->first_rx_desc;
646*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	outl(db->first_rx_desc_dma, ioaddr + DCR3);	/* RX DESC address */
647*2439e4bfSJean-Christophe PLAGNIOL-VILLARD #ifdef DEBUG
648*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	printf("%s(): db->first_tx_desc= 0x%x\n",
649*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 		__FUNCTION__, db->first_tx_desc);
650*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	printf("%s(): db->first_rx_desc_dma= 0x%x\n",
651*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 		__FUNCTION__, db->first_rx_desc_dma);
652*2439e4bfSJean-Christophe PLAGNIOL-VILLARD #endif
653*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	/* Init Transmit chain */
654*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	tmp_buf = db->buf_pool_start;
655*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	tmp_buf_dma = db->buf_pool_dma_start;
656*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	tmp_tx_dma = db->first_tx_desc_dma;
657*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	for (tmp_tx = db->first_tx_desc, i = 0;
658*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 			i < TX_DESC_CNT; i++, tmp_tx++) {
659*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 		tmp_tx->tx_buf_ptr = tmp_buf;
660*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 		tmp_tx->tdes0 = cpu_to_le32(0);
661*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 		tmp_tx->tdes1 = cpu_to_le32(0x81000000);	/* IC, chain */
662*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 		tmp_tx->tdes2 = cpu_to_le32(tmp_buf_dma);
663*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 		tmp_tx_dma += sizeof(struct tx_desc);
664*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 		tmp_tx->tdes3 = cpu_to_le32(tmp_tx_dma);
665*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 		tmp_tx->next_tx_desc = tmp_tx + 1;
666*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 		tmp_buf = tmp_buf + TX_BUF_ALLOC;
667*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 		tmp_buf_dma = tmp_buf_dma + TX_BUF_ALLOC;
668*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	}
669*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	(--tmp_tx)->tdes3 = cpu_to_le32(db->first_tx_desc_dma);
670*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	tmp_tx->next_tx_desc = db->first_tx_desc;
671*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 
672*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	 /* Init Receive descriptor chain */
673*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	tmp_rx_dma = db->first_rx_desc_dma;
674*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	for (tmp_rx = db->first_rx_desc, i = 0; i < RX_DESC_CNT;
675*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 			i++, tmp_rx++) {
676*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 		tmp_rx->rdes0 = cpu_to_le32(0);
677*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 		tmp_rx->rdes1 = cpu_to_le32(0x01000600);
678*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 		tmp_rx_dma += sizeof(struct rx_desc);
679*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 		tmp_rx->rdes3 = cpu_to_le32(tmp_rx_dma);
680*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 		tmp_rx->next_rx_desc = tmp_rx + 1;
681*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	}
682*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	(--tmp_rx)->rdes3 = cpu_to_le32(db->first_rx_desc_dma);
683*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	tmp_rx->next_rx_desc = db->first_rx_desc;
684*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 
685*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	/* pre-allocate Rx buffer */
686*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	allocate_rx_buffer(db);
687*2439e4bfSJean-Christophe PLAGNIOL-VILLARD }
688*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 
689*2439e4bfSJean-Christophe PLAGNIOL-VILLARD /*
690*2439e4bfSJean-Christophe PLAGNIOL-VILLARD  *	Update CR6 value
691*2439e4bfSJean-Christophe PLAGNIOL-VILLARD  *	Firstly stop ULI526X, then written value and start
692*2439e4bfSJean-Christophe PLAGNIOL-VILLARD  */
693*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 
694*2439e4bfSJean-Christophe PLAGNIOL-VILLARD static void update_cr6(u32 cr6_data, unsigned long ioaddr)
695*2439e4bfSJean-Christophe PLAGNIOL-VILLARD {
696*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 
697*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	outl(cr6_data, ioaddr + DCR6);
698*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	udelay(5);
699*2439e4bfSJean-Christophe PLAGNIOL-VILLARD }
700*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 
701*2439e4bfSJean-Christophe PLAGNIOL-VILLARD /*
702*2439e4bfSJean-Christophe PLAGNIOL-VILLARD  *	Allocate rx buffer,
703*2439e4bfSJean-Christophe PLAGNIOL-VILLARD  */
704*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 
705*2439e4bfSJean-Christophe PLAGNIOL-VILLARD static void allocate_rx_buffer(struct uli526x_board_info *db)
706*2439e4bfSJean-Christophe PLAGNIOL-VILLARD {
707*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	int index;
708*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	struct rx_desc *rxptr;
709*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	rxptr = db->first_rx_desc;
710*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	u32 addr;
711*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 
712*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	for (index = 0; index < RX_DESC_CNT; index++) {
713*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 		addr = (u32)NetRxPackets[index];
714*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 		addr += (16 - (addr & 15));
715*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 		rxptr->rx_buf_ptr = (char *) addr;
716*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 		rxptr->rdes2 = cpu_to_le32(addr);
717*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 		rxptr->rdes0 = cpu_to_le32(0x80000000);
718*2439e4bfSJean-Christophe PLAGNIOL-VILLARD #ifdef DEBUG
719*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 		printf("%s(): Number 0x%x:\n", __FUNCTION__, index);
720*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 		printf("%s(): addr 0x%x:\n", __FUNCTION__, addr);
721*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 		printf("%s(): rxptr address = 0x%x\n", __FUNCTION__, rxptr);
722*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 		printf("%s(): rxptr buf address = 0x%x\n", \
723*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 			__FUNCTION__, rxptr->rx_buf_ptr);
724*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 		printf("%s(): rdes2  = 0x%x\n", __FUNCTION__, rxptr->rdes2);
725*2439e4bfSJean-Christophe PLAGNIOL-VILLARD #endif
726*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 		rxptr = rxptr->next_rx_desc;
727*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	}
728*2439e4bfSJean-Christophe PLAGNIOL-VILLARD }
729*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 
730*2439e4bfSJean-Christophe PLAGNIOL-VILLARD /*
731*2439e4bfSJean-Christophe PLAGNIOL-VILLARD  *	Read one word data from the serial ROM
732*2439e4bfSJean-Christophe PLAGNIOL-VILLARD  */
733*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 
734*2439e4bfSJean-Christophe PLAGNIOL-VILLARD static u16 read_srom_word(long ioaddr, int offset)
735*2439e4bfSJean-Christophe PLAGNIOL-VILLARD {
736*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	int i;
737*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	u16 srom_data = 0;
738*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	long cr9_ioaddr = ioaddr + DCR9;
739*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 
740*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	outl(CR9_SROM_READ, cr9_ioaddr);
741*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	outl(CR9_SROM_READ | CR9_SRCS, cr9_ioaddr);
742*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 
743*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	/* Send the Read Command 110b */
744*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	SROM_CLK_WRITE(SROM_DATA_1, cr9_ioaddr);
745*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	SROM_CLK_WRITE(SROM_DATA_1, cr9_ioaddr);
746*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	SROM_CLK_WRITE(SROM_DATA_0, cr9_ioaddr);
747*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 
748*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	/* Send the offset */
749*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	for (i = 5; i >= 0; i--) {
750*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 		srom_data = (offset & (1 << i)) ? SROM_DATA_1 : SROM_DATA_0;
751*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 		SROM_CLK_WRITE(srom_data, cr9_ioaddr);
752*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	}
753*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 
754*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	outl(CR9_SROM_READ | CR9_SRCS, cr9_ioaddr);
755*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 
756*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	for (i = 16; i > 0; i--) {
757*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 		outl(CR9_SROM_READ | CR9_SRCS | CR9_SRCLK, cr9_ioaddr);
758*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 		udelay(5);
759*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 		srom_data = (srom_data << 1) | ((inl(cr9_ioaddr) & CR9_CRDOUT)
760*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 			? 1 : 0);
761*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 		outl(CR9_SROM_READ | CR9_SRCS, cr9_ioaddr);
762*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 		udelay(5);
763*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	}
764*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 
765*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	outl(CR9_SROM_READ, cr9_ioaddr);
766*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	return srom_data;
767*2439e4bfSJean-Christophe PLAGNIOL-VILLARD }
768*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 
769*2439e4bfSJean-Christophe PLAGNIOL-VILLARD /*
770*2439e4bfSJean-Christophe PLAGNIOL-VILLARD  *	Set 10/100 phyxcer capability
771*2439e4bfSJean-Christophe PLAGNIOL-VILLARD  *	AUTO mode : phyxcer register4 is NIC capability
772*2439e4bfSJean-Christophe PLAGNIOL-VILLARD  *	Force mode: phyxcer register4 is the force media
773*2439e4bfSJean-Christophe PLAGNIOL-VILLARD  */
774*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 
775*2439e4bfSJean-Christophe PLAGNIOL-VILLARD static void uli526x_set_phyxcer(struct uli526x_board_info *db)
776*2439e4bfSJean-Christophe PLAGNIOL-VILLARD {
777*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	u16 phy_reg;
778*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 
779*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	/* Phyxcer capability setting */
780*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	phy_reg = phy_read(db->ioaddr, db->phy_addr, 4, db->chip_id) & ~0x01e0;
781*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 
782*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	if (db->media_mode & ULI526X_AUTO) {
783*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 		/* AUTO Mode */
784*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 		phy_reg |= db->PHY_reg4;
785*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	} else {
786*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 		/* Force Mode */
787*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 		switch (db->media_mode) {
788*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 		case ULI526X_10MHF: phy_reg |= 0x20; break;
789*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 		case ULI526X_10MFD: phy_reg |= 0x40; break;
790*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 		case ULI526X_100MHF: phy_reg |= 0x80; break;
791*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 		case ULI526X_100MFD: phy_reg |= 0x100; break;
792*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 		}
793*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 
794*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	}
795*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 
796*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	/* Write new capability to Phyxcer Reg4 */
797*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	if (!(phy_reg & 0x01e0)) {
798*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 		phy_reg |= db->PHY_reg4;
799*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 		db->media_mode |= ULI526X_AUTO;
800*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	}
801*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	phy_write(db->ioaddr, db->phy_addr, 4, phy_reg, db->chip_id);
802*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 
803*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	/* Restart Auto-Negotiation */
804*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	phy_write(db->ioaddr, db->phy_addr, 0, 0x1200, db->chip_id);
805*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	udelay(50);
806*2439e4bfSJean-Christophe PLAGNIOL-VILLARD }
807*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 
808*2439e4bfSJean-Christophe PLAGNIOL-VILLARD /*
809*2439e4bfSJean-Christophe PLAGNIOL-VILLARD  *	Write a word to Phy register
810*2439e4bfSJean-Christophe PLAGNIOL-VILLARD  */
811*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 
812*2439e4bfSJean-Christophe PLAGNIOL-VILLARD static void phy_write(unsigned long iobase, u8 phy_addr, u8 offset,
813*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	u16 phy_data, u32 chip_id)
814*2439e4bfSJean-Christophe PLAGNIOL-VILLARD {
815*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	u16 i;
816*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	unsigned long ioaddr;
817*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 
818*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	if (chip_id == PCI_ULI5263_ID) {
819*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 		phy_writeby_cr10(iobase, phy_addr, offset, phy_data);
820*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 		return;
821*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	}
822*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	/* M5261/M5263 Chip */
823*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	ioaddr = iobase + DCR9;
824*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 
825*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	/* Send 33 synchronization clock to Phy controller */
826*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	for (i = 0; i < 35; i++)
827*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 		phy_write_1bit(ioaddr, PHY_DATA_1, chip_id);
828*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 
829*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	/* Send start command(01) to Phy */
830*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	phy_write_1bit(ioaddr, PHY_DATA_0, chip_id);
831*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	phy_write_1bit(ioaddr, PHY_DATA_1, chip_id);
832*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 
833*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	/* Send write command(01) to Phy */
834*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	phy_write_1bit(ioaddr, PHY_DATA_0, chip_id);
835*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	phy_write_1bit(ioaddr, PHY_DATA_1, chip_id);
836*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 
837*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	/* Send Phy address */
838*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	for (i = 0x10; i > 0; i = i >> 1)
839*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 		phy_write_1bit(ioaddr, phy_addr & i ?
840*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 			PHY_DATA_1 : PHY_DATA_0, chip_id);
841*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 
842*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	/* Send register address */
843*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	for (i = 0x10; i > 0; i = i >> 1)
844*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 		phy_write_1bit(ioaddr, offset & i ?
845*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 			PHY_DATA_1 : PHY_DATA_0, chip_id);
846*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 
847*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	/* written trasnition */
848*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	phy_write_1bit(ioaddr, PHY_DATA_1, chip_id);
849*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	phy_write_1bit(ioaddr, PHY_DATA_0, chip_id);
850*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 
851*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	/* Write a word data to PHY controller */
852*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	for (i = 0x8000; i > 0; i >>= 1)
853*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 		phy_write_1bit(ioaddr, phy_data & i ?
854*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 			PHY_DATA_1 : PHY_DATA_0, chip_id);
855*2439e4bfSJean-Christophe PLAGNIOL-VILLARD }
856*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 
857*2439e4bfSJean-Christophe PLAGNIOL-VILLARD /*
858*2439e4bfSJean-Christophe PLAGNIOL-VILLARD  *	Read a word data from phy register
859*2439e4bfSJean-Christophe PLAGNIOL-VILLARD  */
860*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 
861*2439e4bfSJean-Christophe PLAGNIOL-VILLARD static u16 phy_read(unsigned long iobase, u8 phy_addr, u8 offset, u32 chip_id)
862*2439e4bfSJean-Christophe PLAGNIOL-VILLARD {
863*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	int i;
864*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	u16 phy_data;
865*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	unsigned long ioaddr;
866*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 
867*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	if (chip_id == PCI_ULI5263_ID)
868*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 		return phy_readby_cr10(iobase, phy_addr, offset);
869*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	/* M5261/M5263 Chip */
870*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	ioaddr = iobase + DCR9;
871*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 
872*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	/* Send 33 synchronization clock to Phy controller */
873*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	for (i = 0; i < 35; i++)
874*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 		phy_write_1bit(ioaddr, PHY_DATA_1, chip_id);
875*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 
876*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	/* Send start command(01) to Phy */
877*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	phy_write_1bit(ioaddr, PHY_DATA_0, chip_id);
878*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	phy_write_1bit(ioaddr, PHY_DATA_1, chip_id);
879*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 
880*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	/* Send read command(10) to Phy */
881*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	phy_write_1bit(ioaddr, PHY_DATA_1, chip_id);
882*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	phy_write_1bit(ioaddr, PHY_DATA_0, chip_id);
883*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 
884*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	/* Send Phy address */
885*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	for (i = 0x10; i > 0; i = i >> 1)
886*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 		phy_write_1bit(ioaddr, phy_addr & i ?
887*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 			PHY_DATA_1 : PHY_DATA_0, chip_id);
888*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 
889*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	/* Send register address */
890*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	for (i = 0x10; i > 0; i = i >> 1)
891*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 		phy_write_1bit(ioaddr, offset & i ?
892*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 			PHY_DATA_1 : PHY_DATA_0, chip_id);
893*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 
894*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	/* Skip transition state */
895*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	phy_read_1bit(ioaddr, chip_id);
896*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 
897*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	/* read 16bit data */
898*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	for (phy_data = 0, i = 0; i < 16; i++) {
899*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 		phy_data <<= 1;
900*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 		phy_data |= phy_read_1bit(ioaddr, chip_id);
901*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	}
902*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 
903*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	return phy_data;
904*2439e4bfSJean-Christophe PLAGNIOL-VILLARD }
905*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 
906*2439e4bfSJean-Christophe PLAGNIOL-VILLARD static u16 phy_readby_cr10(unsigned long iobase, u8 phy_addr, u8 offset)
907*2439e4bfSJean-Christophe PLAGNIOL-VILLARD {
908*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	unsigned long ioaddr, cr10_value;
909*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 
910*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	ioaddr = iobase + DCR10;
911*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	cr10_value = phy_addr;
912*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	cr10_value = (cr10_value<<5) + offset;
913*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	cr10_value = (cr10_value<<16) + 0x08000000;
914*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	outl(cr10_value, ioaddr);
915*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	udelay(1);
916*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	while (1) {
917*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 		cr10_value = inl(ioaddr);
918*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 		if (cr10_value & 0x10000000)
919*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 			break;
920*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	}
921*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	return (cr10_value&0x0ffff);
922*2439e4bfSJean-Christophe PLAGNIOL-VILLARD }
923*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 
924*2439e4bfSJean-Christophe PLAGNIOL-VILLARD static void phy_writeby_cr10(unsigned long iobase, u8 phy_addr,
925*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	u8 offset, u16 phy_data)
926*2439e4bfSJean-Christophe PLAGNIOL-VILLARD {
927*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	unsigned long ioaddr, cr10_value;
928*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 
929*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	ioaddr = iobase + DCR10;
930*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	cr10_value = phy_addr;
931*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	cr10_value = (cr10_value<<5) + offset;
932*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	cr10_value = (cr10_value<<16) + 0x04000000 + phy_data;
933*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	outl(cr10_value, ioaddr);
934*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	udelay(1);
935*2439e4bfSJean-Christophe PLAGNIOL-VILLARD }
936*2439e4bfSJean-Christophe PLAGNIOL-VILLARD /*
937*2439e4bfSJean-Christophe PLAGNIOL-VILLARD  *	Write one bit data to Phy Controller
938*2439e4bfSJean-Christophe PLAGNIOL-VILLARD  */
939*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 
940*2439e4bfSJean-Christophe PLAGNIOL-VILLARD static void phy_write_1bit(unsigned long ioaddr, u32 phy_data, u32 chip_id)
941*2439e4bfSJean-Christophe PLAGNIOL-VILLARD {
942*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	outl(phy_data , ioaddr);			/* MII Clock Low */
943*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	udelay(1);
944*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	outl(phy_data  | MDCLKH, ioaddr);	/* MII Clock High */
945*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	udelay(1);
946*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	outl(phy_data , ioaddr);			/* MII Clock Low */
947*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	udelay(1);
948*2439e4bfSJean-Christophe PLAGNIOL-VILLARD }
949*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 
950*2439e4bfSJean-Christophe PLAGNIOL-VILLARD /*
951*2439e4bfSJean-Christophe PLAGNIOL-VILLARD  *	Read one bit phy data from PHY controller
952*2439e4bfSJean-Christophe PLAGNIOL-VILLARD  */
953*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 
954*2439e4bfSJean-Christophe PLAGNIOL-VILLARD static u16 phy_read_1bit(unsigned long ioaddr, u32 chip_id)
955*2439e4bfSJean-Christophe PLAGNIOL-VILLARD {
956*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	u16 phy_data;
957*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 
958*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	outl(0x50000 , ioaddr);
959*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	udelay(1);
960*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	phy_data = (inl(ioaddr) >> 19) & 0x1;
961*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	outl(0x40000 , ioaddr);
962*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	udelay(1);
963*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 
964*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	return phy_data;
965*2439e4bfSJean-Christophe PLAGNIOL-VILLARD }
966*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 
967*2439e4bfSJean-Christophe PLAGNIOL-VILLARD /*
968*2439e4bfSJean-Christophe PLAGNIOL-VILLARD  * Set MAC address to ID Table
969*2439e4bfSJean-Christophe PLAGNIOL-VILLARD  */
970*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 
971*2439e4bfSJean-Christophe PLAGNIOL-VILLARD static void set_mac_addr(struct eth_device *dev)
972*2439e4bfSJean-Christophe PLAGNIOL-VILLARD {
973*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	int i;
974*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	u16 addr;
975*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	struct uli526x_board_info *db = dev->priv;
976*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	outl(0x10000, db->ioaddr + DCR0);	/* Diagnosis mode */
977*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	/* Reset dianostic pointer port */
978*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	outl(0x1c0, db->ioaddr + DCR13);
979*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	outl(0, db->ioaddr + DCR14);	/* Clear reset port */
980*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	outl(0x10, db->ioaddr + DCR14);	/* Reset ID Table pointer */
981*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	outl(0, db->ioaddr + DCR14);	/* Clear reset port */
982*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	outl(0, db->ioaddr + DCR13);	/* Clear CR13 */
983*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	/* Select ID Table access port */
984*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	outl(0x1b0, db->ioaddr + DCR13);
985*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	/* Read MAC address from CR14 */
986*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	for (i = 0; i < 3; i++) {
987*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 		addr = dev->enetaddr[2 * i] | (dev->enetaddr[2 * i + 1] << 8);
988*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 		outl(addr, db->ioaddr + DCR14);
989*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	}
990*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	/* write end */
991*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	outl(0, db->ioaddr + DCR13);	/* Clear CR13 */
992*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	outl(0, db->ioaddr + DCR0);	/* Clear CR0 */
993*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	udelay(10);
994*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 	return;
995*2439e4bfSJean-Christophe PLAGNIOL-VILLARD }
996*2439e4bfSJean-Christophe PLAGNIOL-VILLARD #endif
997