xref: /minix3/minix/drivers/net/lan8710a/lan8710a.c (revision d4dd6511b9dc029206ce2c925ed135e16555aae4)
1433d6423SLionel Sambuc #include <minix/drivers.h>
2433d6423SLionel Sambuc #include <minix/netdriver.h>
3433d6423SLionel Sambuc #include <minix/board.h>
45af3c256SDavid van Moolenbroek #include <sys/mman.h>
5433d6423SLionel Sambuc #include "assert.h"
6433d6423SLionel Sambuc #include "lan8710a.h"
7433d6423SLionel Sambuc #include "lan8710a_reg.h"
8433d6423SLionel Sambuc 
9433d6423SLionel Sambuc /* Local functions */
10f7df02e7SDavid van Moolenbroek static int lan8710a_init(unsigned int instance, netdriver_addr_t *addr,
11f7df02e7SDavid van Moolenbroek 	uint32_t *caps, unsigned int *ticks);
12433d6423SLionel Sambuc static void lan8710a_stop(void);
135af3c256SDavid van Moolenbroek static ssize_t lan8710a_recv(struct netdriver_data *data, size_t max);
145af3c256SDavid van Moolenbroek static int lan8710a_send(struct netdriver_data *data, size_t size);
155af3c256SDavid van Moolenbroek static void lan8710a_intr(unsigned int mask);
16f7df02e7SDavid van Moolenbroek static void lan8710a_tick(void);
175af3c256SDavid van Moolenbroek 
185af3c256SDavid van Moolenbroek static void lan8710a_enable_interrupt(int interrupt);
195af3c256SDavid van Moolenbroek static void lan8710a_map_regs(void);
20433d6423SLionel Sambuc static void lan8710a_dma_config_tx(u8_t desc_idx);
21433d6423SLionel Sambuc static void lan8710a_dma_reset_init(void);
22f7df02e7SDavid van Moolenbroek static void lan8710a_init_addr(netdriver_addr_t *addr, unsigned int instance);
23433d6423SLionel Sambuc static void lan8710a_init_desc(void);
24433d6423SLionel Sambuc static void lan8710a_init_mdio(void);
25f7df02e7SDavid van Moolenbroek static int lan8710a_init_hw(netdriver_addr_t *addr, unsigned int instance);
265af3c256SDavid van Moolenbroek static void lan8710a_reset_hw(void);
27433d6423SLionel Sambuc 
28433d6423SLionel Sambuc static void lan8710a_phy_write(u32_t reg, u32_t value);
29433d6423SLionel Sambuc static u32_t lan8710a_phy_read(u32_t reg);
30433d6423SLionel Sambuc 
31433d6423SLionel Sambuc static u32_t lan8710a_reg_read(volatile u32_t *reg);
32433d6423SLionel Sambuc static void lan8710a_reg_write(volatile u32_t *reg, u32_t value);
33433d6423SLionel Sambuc static void lan8710a_reg_set(volatile u32_t *reg, u32_t value);
34433d6423SLionel Sambuc static void lan8710a_reg_unset(volatile u32_t *reg, u32_t value);
35433d6423SLionel Sambuc 
36433d6423SLionel Sambuc /* Local variables */
37433d6423SLionel Sambuc static lan8710a_t lan8710a_state;
38433d6423SLionel Sambuc 
395af3c256SDavid van Moolenbroek static const struct netdriver lan8710a_table = {
40f7df02e7SDavid van Moolenbroek 	.ndr_name	= "cpsw",
415af3c256SDavid van Moolenbroek 	.ndr_init	= lan8710a_init,
425af3c256SDavid van Moolenbroek 	.ndr_stop	= lan8710a_stop,
435af3c256SDavid van Moolenbroek 	.ndr_recv	= lan8710a_recv,
445af3c256SDavid van Moolenbroek 	.ndr_send	= lan8710a_send,
45f7df02e7SDavid van Moolenbroek 	.ndr_intr	= lan8710a_intr,
46f7df02e7SDavid van Moolenbroek 	.ndr_tick	= lan8710a_tick
475af3c256SDavid van Moolenbroek };
48433d6423SLionel Sambuc 
49433d6423SLionel Sambuc /*============================================================================*
50433d6423SLionel Sambuc  *				main					      *
51433d6423SLionel Sambuc  *============================================================================*/
52433d6423SLionel Sambuc int
main(int argc,char * argv[])53433d6423SLionel Sambuc main(int argc, char *argv[])
54433d6423SLionel Sambuc {
55433d6423SLionel Sambuc 	struct machine machine;
56433d6423SLionel Sambuc 
57433d6423SLionel Sambuc 	env_setargs(argc, argv);
58433d6423SLionel Sambuc 
595af3c256SDavid van Moolenbroek 	sys_getmachine(&machine);
605af3c256SDavid van Moolenbroek 	if (BOARD_IS_BB(machine.board_id))
615af3c256SDavid van Moolenbroek 		netdriver_task(&lan8710a_table);
62433d6423SLionel Sambuc 
63433d6423SLionel Sambuc 	return EXIT_SUCCESS;
64433d6423SLionel Sambuc }
65433d6423SLionel Sambuc 
66433d6423SLionel Sambuc /*============================================================================*
675af3c256SDavid van Moolenbroek  *				lan8710a_init				      *
68433d6423SLionel Sambuc  *============================================================================*/
69433d6423SLionel Sambuc static int
lan8710a_init(unsigned int instance,netdriver_addr_t * addr,uint32_t * caps,unsigned int * ticks)70f7df02e7SDavid van Moolenbroek lan8710a_init(unsigned int instance, netdriver_addr_t * addr, uint32_t * caps,
71f7df02e7SDavid van Moolenbroek 	unsigned int * ticks)
72433d6423SLionel Sambuc {
73433d6423SLionel Sambuc 	/* Initialize the ethernet driver. */
74433d6423SLionel Sambuc 
75433d6423SLionel Sambuc 	/* Clear state. */
76433d6423SLionel Sambuc 	memset(&lan8710a_state, 0, sizeof(lan8710a_state));
77433d6423SLionel Sambuc 
78433d6423SLionel Sambuc 	/* Initialize driver. */
795af3c256SDavid van Moolenbroek 	lan8710a_map_regs();
80433d6423SLionel Sambuc 
81f7df02e7SDavid van Moolenbroek 	lan8710a_init_hw(addr, instance);
82433d6423SLionel Sambuc 
83f7df02e7SDavid van Moolenbroek 	*caps = NDEV_CAP_MCAST | NDEV_CAP_BCAST;
84f7df02e7SDavid van Moolenbroek 	*ticks = sys_hz(); /* update statistics once a second */
85433d6423SLionel Sambuc 	return OK;
86433d6423SLionel Sambuc }
87433d6423SLionel Sambuc 
88433d6423SLionel Sambuc /*============================================================================*
89433d6423SLionel Sambuc  *				lan8710a_enable_interrupt		      *
90433d6423SLionel Sambuc  *============================================================================*/
91433d6423SLionel Sambuc static void
lan8710a_enable_interrupt(int interrupt)925af3c256SDavid van Moolenbroek lan8710a_enable_interrupt(int interrupt)
93433d6423SLionel Sambuc {
94433d6423SLionel Sambuc 	int r;
95433d6423SLionel Sambuc 
96433d6423SLionel Sambuc 	if (interrupt & RX_INT) {
97433d6423SLionel Sambuc 		if ((r = sys_irqenable(&lan8710a_state.irq_rx_hook)) != OK) {
98433d6423SLionel Sambuc 			panic("sys_irqenable failed: %d", r);
99433d6423SLionel Sambuc 		}
100433d6423SLionel Sambuc 	}
101433d6423SLionel Sambuc 	if (interrupt & TX_INT) {
102433d6423SLionel Sambuc 		if ((r = sys_irqenable(&lan8710a_state.irq_tx_hook)) != OK) {
103433d6423SLionel Sambuc 			panic("sys_irqenable failed: %d", r);
104433d6423SLionel Sambuc 		}
105433d6423SLionel Sambuc 	}
106433d6423SLionel Sambuc }
1075af3c256SDavid van Moolenbroek 
108433d6423SLionel Sambuc /*============================================================================*
1095af3c256SDavid van Moolenbroek  *				lan8710a_intr				      *
110433d6423SLionel Sambuc  *============================================================================*/
111433d6423SLionel Sambuc static void
lan8710a_intr(unsigned int mask)1125af3c256SDavid van Moolenbroek lan8710a_intr(unsigned int mask)
113433d6423SLionel Sambuc {
114433d6423SLionel Sambuc 	u32_t dma_status;
115433d6423SLionel Sambuc 
116433d6423SLionel Sambuc 	/* Check the card for interrupt reason(s). */
117433d6423SLionel Sambuc 	u32_t rx_stat = lan8710a_reg_read(CPSW_WR_C0_RX_STAT);
118433d6423SLionel Sambuc 	u32_t tx_stat = lan8710a_reg_read(CPSW_WR_C0_TX_STAT);
119433d6423SLionel Sambuc 	u32_t cp;
120433d6423SLionel Sambuc 
121433d6423SLionel Sambuc 	/* Handle interrupts. */
122433d6423SLionel Sambuc 	if (rx_stat) {
123433d6423SLionel Sambuc 		cp = lan8710a_reg_read(CPDMA_STRAM_RX_CP(0));
124433d6423SLionel Sambuc 
1255af3c256SDavid van Moolenbroek 		netdriver_recv();
126433d6423SLionel Sambuc 
127433d6423SLionel Sambuc 		lan8710a_reg_write(CPDMA_STRAM_RX_CP(0), cp);
128433d6423SLionel Sambuc 		lan8710a_reg_write(CPDMA_EOI_VECTOR, RX_INT);
129433d6423SLionel Sambuc 	}
130433d6423SLionel Sambuc 	if (tx_stat) {
131433d6423SLionel Sambuc 		cp = lan8710a_reg_read(CPDMA_STRAM_TX_CP(0));
132433d6423SLionel Sambuc 
133433d6423SLionel Sambuc 		/* Disabling channels, where Tx interrupt occurred */
134433d6423SLionel Sambuc 		lan8710a_reg_set(CPDMA_TX_INTMASK_CLEAR, tx_stat);
135433d6423SLionel Sambuc 
1365af3c256SDavid van Moolenbroek 		netdriver_send();
137433d6423SLionel Sambuc 
138433d6423SLionel Sambuc 		lan8710a_reg_write(CPDMA_STRAM_TX_CP(0), cp);
139433d6423SLionel Sambuc 		lan8710a_reg_write(CPDMA_EOI_VECTOR, TX_INT);
140433d6423SLionel Sambuc 	}
141433d6423SLionel Sambuc 
142433d6423SLionel Sambuc 	dma_status = lan8710a_reg_read(CPDMA_STATUS);
143433d6423SLionel Sambuc 
144433d6423SLionel Sambuc 	if (dma_status & CPDMA_ERROR) {
145433d6423SLionel Sambuc 		LAN8710A_DEBUG_PRINT(("CPDMA error: 0x%X, reset", dma_status));
146433d6423SLionel Sambuc 		lan8710a_dma_reset_init();
147433d6423SLionel Sambuc 	}
148433d6423SLionel Sambuc 
149433d6423SLionel Sambuc 	/* Re-enable Rx interrupt. */
1505af3c256SDavid van Moolenbroek 	if (mask & (1 << RX_INT))
151433d6423SLionel Sambuc 		lan8710a_enable_interrupt(RX_INT);
152433d6423SLionel Sambuc 
153433d6423SLionel Sambuc 	/* Re-enable Tx interrupt. */
1545af3c256SDavid van Moolenbroek 	if (mask & (1 << TX_INT))
155433d6423SLionel Sambuc 		lan8710a_enable_interrupt(TX_INT);
156433d6423SLionel Sambuc }
157433d6423SLionel Sambuc 
158433d6423SLionel Sambuc /*============================================================================*
159433d6423SLionel Sambuc  *				lan8710a_init_addr			      *
160433d6423SLionel Sambuc  *============================================================================*/
161433d6423SLionel Sambuc static void
lan8710a_init_addr(netdriver_addr_t * addr,unsigned int instance)162f7df02e7SDavid van Moolenbroek lan8710a_init_addr(netdriver_addr_t * addr, unsigned int instance)
163433d6423SLionel Sambuc {
164433d6423SLionel Sambuc 	static char eakey[]= LAN8710A_ENVVAR "#_EA";
165433d6423SLionel Sambuc 	static char eafmt[]= "x:x:x:x:x:x";
166433d6423SLionel Sambuc 	int i;
167433d6423SLionel Sambuc 	long v;
168433d6423SLionel Sambuc 
169433d6423SLionel Sambuc 	/*
170433d6423SLionel Sambuc 	 * Do we have a user defined ethernet address?
171433d6423SLionel Sambuc 	 */
172f7df02e7SDavid van Moolenbroek 	eakey[sizeof(LAN8710A_ENVVAR)-1] = '0' + instance;
173433d6423SLionel Sambuc 
174433d6423SLionel Sambuc 	for (i= 0; i < 6; i++) {
175433d6423SLionel Sambuc 		if (env_parse(eakey, eafmt, i, &v, 0x00L, 0xFFL) != EP_SET)
176433d6423SLionel Sambuc 			break;
177433d6423SLionel Sambuc 		else
178f7df02e7SDavid van Moolenbroek 			addr->na_addr[i] = v;
179433d6423SLionel Sambuc 	}
1805af3c256SDavid van Moolenbroek 	if (i == 6)
1815af3c256SDavid van Moolenbroek 		return;
1825af3c256SDavid van Moolenbroek 
1835af3c256SDavid van Moolenbroek 	/*
1845af3c256SDavid van Moolenbroek 	 * No; get the address from the chip itself.
1855af3c256SDavid van Moolenbroek 	 */
186f7df02e7SDavid van Moolenbroek 	addr->na_addr[0] = lan8710a_reg_read(CTRL_MAC_ID0_HI) & 0xFF;
187f7df02e7SDavid van Moolenbroek 	addr->na_addr[1] = (lan8710a_reg_read(CTRL_MAC_ID0_HI) >> 8) & 0xFF;
188f7df02e7SDavid van Moolenbroek 	addr->na_addr[2] = (lan8710a_reg_read(CTRL_MAC_ID0_HI) >> 16) & 0xFF;
189f7df02e7SDavid van Moolenbroek 	addr->na_addr[3] = (lan8710a_reg_read(CTRL_MAC_ID0_HI) >> 24) & 0xFF;
190f7df02e7SDavid van Moolenbroek 	addr->na_addr[4] = lan8710a_reg_read(CTRL_MAC_ID0_LO) & 0xFF;
191f7df02e7SDavid van Moolenbroek 	addr->na_addr[5] = (lan8710a_reg_read(CTRL_MAC_ID0_LO) >> 8) & 0xFF;
192433d6423SLionel Sambuc }
193433d6423SLionel Sambuc 
194433d6423SLionel Sambuc /*============================================================================*
195433d6423SLionel Sambuc  *				lan8710a_map_regs			      *
196433d6423SLionel Sambuc  *============================================================================*/
197433d6423SLionel Sambuc static void
lan8710a_map_regs(void)198433d6423SLionel Sambuc lan8710a_map_regs(void)
199433d6423SLionel Sambuc {
200433d6423SLionel Sambuc 	struct minix_mem_range mr;
201433d6423SLionel Sambuc 	mr.mr_base = CM_PER_BASE_ADR;
202433d6423SLionel Sambuc 	mr.mr_limit = CM_PER_BASE_ADR + MEMORY_LIMIT;
203433d6423SLionel Sambuc 
204433d6423SLionel Sambuc 	if (sys_privctl(SELF, SYS_PRIV_ADD_MEM, &mr) != 0) {
205433d6423SLionel Sambuc 		panic("Unable to request permission to map memory");
206433d6423SLionel Sambuc 	}
207433d6423SLionel Sambuc 	lan8710a_state.regs_cp_per =
208433d6423SLionel Sambuc 		(vir_bytes)vm_map_phys(SELF, (void *)CM_PER_BASE_ADR, 512);
209433d6423SLionel Sambuc 	if ((void *)lan8710a_state.regs_cp_per == MAP_FAILED) {
210433d6423SLionel Sambuc 		panic("lan8710a_state.regs_cp_per: vm_map_phys failed");
211433d6423SLionel Sambuc 	}
212433d6423SLionel Sambuc 	lan8710a_state.regs_cpdma_stram =
213433d6423SLionel Sambuc 		(vir_bytes)vm_map_phys(SELF, (void *)CPDMA_STRAM_BASE_ADR, 512);
214433d6423SLionel Sambuc 	if ((void *)lan8710a_state.regs_cpdma_stram == MAP_FAILED) {
215433d6423SLionel Sambuc 		panic("lan8710a_state.regs_cpdma_stram: vm_map_phys failed");
216433d6423SLionel Sambuc 	}
217433d6423SLionel Sambuc 	lan8710a_state.regs_cpsw_cpdma =
218433d6423SLionel Sambuc 		(vir_bytes)vm_map_phys(SELF, (void *)CPSW_CPDMA_BASE_ADR, 512);
219433d6423SLionel Sambuc 	if ((void *)lan8710a_state.regs_cpsw_cpdma == MAP_FAILED) {
220433d6423SLionel Sambuc 		panic("lan8710a_state.regs_cpsw_cpdma: vm_map_phys failed");
221433d6423SLionel Sambuc 	}
222433d6423SLionel Sambuc 	lan8710a_state.regs_cpsw_ale =
223433d6423SLionel Sambuc 		(vir_bytes)vm_map_phys(SELF, (void *)CPSW_ALE_BASE_ADR, 256);
224433d6423SLionel Sambuc 	if ((void *)lan8710a_state.regs_cpsw_ale == MAP_FAILED) {
225433d6423SLionel Sambuc 		panic("lan8710a_state.regs_cpsw_ale: vm_map_phys failed");
226433d6423SLionel Sambuc 	}
227433d6423SLionel Sambuc 	lan8710a_state.regs_cpsw_sl =
228433d6423SLionel Sambuc 		(vir_bytes)vm_map_phys(SELF, (void *)CPSW_SL_BASE_ADR, 512);
229433d6423SLionel Sambuc 	if ((void *)lan8710a_state.regs_cpsw_sl == MAP_FAILED) {
230433d6423SLionel Sambuc 		panic("lan8710a_state.regs_cpsw_sl: vm_map_phys failed");
231433d6423SLionel Sambuc 	}
232433d6423SLionel Sambuc 	lan8710a_state.regs_cpsw_ss =
233433d6423SLionel Sambuc 		(vir_bytes)vm_map_phys(SELF, (void *)CPSW_SS_BASE_ADR, 512);
234433d6423SLionel Sambuc 	if ((void *)lan8710a_state.regs_cpsw_ss == MAP_FAILED) {
235433d6423SLionel Sambuc 		panic("lan8710a_state.regs_cpsw_ss: vm_map_phys failed");
236433d6423SLionel Sambuc 	}
237433d6423SLionel Sambuc 	lan8710a_state.regs_cpsw_wr =
238433d6423SLionel Sambuc 		(vir_bytes)vm_map_phys(SELF, (void *)CPSW_WR_BASE_ADR, 512);
239433d6423SLionel Sambuc 	if ((void *)lan8710a_state.regs_cpsw_wr == MAP_FAILED) {
240433d6423SLionel Sambuc 		panic("lan8710a_state.regs_cpsw_wr: vm_map_phys failed");
241433d6423SLionel Sambuc 	}
242433d6423SLionel Sambuc 	lan8710a_state.regs_ctrl_mod =
243433d6423SLionel Sambuc 		(vir_bytes)vm_map_phys(SELF, (void *)CTRL_MOD_BASE_ADR, 2560);
244433d6423SLionel Sambuc 	if ((void *)lan8710a_state.regs_ctrl_mod == MAP_FAILED) {
245433d6423SLionel Sambuc 		panic("lan8710a_state.regs_ctrl_mod: vm_map_phys failed");
246433d6423SLionel Sambuc 	}
247433d6423SLionel Sambuc 	lan8710a_state.regs_intc =
248433d6423SLionel Sambuc 		(vir_bytes)vm_map_phys(SELF, (void *)INTC_BASE_ADR, 512);
249433d6423SLionel Sambuc 	if ((void *)lan8710a_state.regs_intc == MAP_FAILED) {
250433d6423SLionel Sambuc 		panic("lan8710a_state.regs_intc: vm_map_phys failed");
251433d6423SLionel Sambuc 	}
252433d6423SLionel Sambuc 	lan8710a_state.regs_mdio =
253433d6423SLionel Sambuc 		(vir_bytes)vm_map_phys(SELF, (void *)MDIO_BASE_ADDR, 512);
254433d6423SLionel Sambuc 	if ((void *)lan8710a_state.regs_mdio == MAP_FAILED) {
255433d6423SLionel Sambuc 		panic("lan8710a_state.regs_mdio: vm_map_phys failed");
256433d6423SLionel Sambuc 	}
257433d6423SLionel Sambuc 
258433d6423SLionel Sambuc 	mr.mr_base = BEGINNING_DESC_MEM;
259433d6423SLionel Sambuc 	mr.mr_limit = BEGINNING_DESC_MEM + DESC_MEMORY_LIMIT;
260433d6423SLionel Sambuc 
261433d6423SLionel Sambuc 	if (sys_privctl(SELF, SYS_PRIV_ADD_MEM, &mr) != 0) {
262433d6423SLionel Sambuc 		panic("Unable to request permission to map memory");
263433d6423SLionel Sambuc 	}
264433d6423SLionel Sambuc 	lan8710a_state.rx_desc_phy = BEGINNING_RX_DESC_MEM;
265433d6423SLionel Sambuc 	lan8710a_state.tx_desc_phy = BEGINNING_TX_DESC_MEM;
266433d6423SLionel Sambuc 	lan8710a_state.rx_desc = (lan8710a_desc_t *)vm_map_phys(SELF,
267433d6423SLionel Sambuc 				(void *)lan8710a_state.rx_desc_phy, 1024);
268433d6423SLionel Sambuc 	if ((void *)lan8710a_state.rx_desc == MAP_FAILED) {
269433d6423SLionel Sambuc 		panic("lan8710a_state.rx_desc: vm_map_phys failed");
270433d6423SLionel Sambuc 	}
271433d6423SLionel Sambuc 	lan8710a_state.tx_desc = (lan8710a_desc_t *)vm_map_phys(SELF,
272433d6423SLionel Sambuc 				(void *)lan8710a_state.tx_desc_phy, 1024);
273433d6423SLionel Sambuc 	if ((void *)lan8710a_state.tx_desc == MAP_FAILED) {
274433d6423SLionel Sambuc 		panic("lan8710a_state.tx_desc: vm_map_phys failed");
275433d6423SLionel Sambuc 	}
276433d6423SLionel Sambuc 
277433d6423SLionel Sambuc 	mr.mr_base = CPSW_STATS_BASE_ADR;
278433d6423SLionel Sambuc 	mr.mr_limit = CPSW_STATS_BASE_ADR + CPSW_STATS_MEM_LIMIT;
279433d6423SLionel Sambuc 
280433d6423SLionel Sambuc 	if (sys_privctl(SELF, SYS_PRIV_ADD_MEM, &mr) != 0) {
281433d6423SLionel Sambuc 		panic("Unable to request permission to map memory");
282433d6423SLionel Sambuc 	}
283433d6423SLionel Sambuc 	lan8710a_state.regs_cpsw_stats =
284433d6423SLionel Sambuc 		(vir_bytes)vm_map_phys(SELF, (void *)CPSW_STATS_BASE_ADR, 256);
285433d6423SLionel Sambuc 	if ((void *)lan8710a_state.regs_cpsw_stats == MAP_FAILED) {
286433d6423SLionel Sambuc 		panic("lan8710a_state.regs_cpsw_stats: vm_map_phys failed");
287433d6423SLionel Sambuc 	}
288433d6423SLionel Sambuc }
289433d6423SLionel Sambuc 
290433d6423SLionel Sambuc /*============================================================================*
291f7df02e7SDavid van Moolenbroek  *				lan8710a_update_stats			      *
292433d6423SLionel Sambuc  *============================================================================*/
293433d6423SLionel Sambuc static void
lan8710a_update_stats(void)294f7df02e7SDavid van Moolenbroek lan8710a_update_stats(void)
295433d6423SLionel Sambuc {
296f7df02e7SDavid van Moolenbroek 	uint32_t val;
297f7df02e7SDavid van Moolenbroek 
298f7df02e7SDavid van Moolenbroek 	/*
299f7df02e7SDavid van Moolenbroek 	 * AM335x Technical Reference (SPRUH73J) Sec. 14.3.2.20: statistics
300f7df02e7SDavid van Moolenbroek 	 * registers are decrement-on-write when any of the statistics port
301f7df02e7SDavid van Moolenbroek 	 * enable bits are set.
302f7df02e7SDavid van Moolenbroek 	 */
303f7df02e7SDavid van Moolenbroek 	val = lan8710a_reg_read(CPSW_STAT_RX_CRC_ERR);
304f7df02e7SDavid van Moolenbroek 	lan8710a_reg_write(CPSW_STAT_RX_CRC_ERR, val);
305f7df02e7SDavid van Moolenbroek 	netdriver_stat_ierror(val);
306f7df02e7SDavid van Moolenbroek 
307f7df02e7SDavid van Moolenbroek 	val = lan8710a_reg_read(CPSW_STAT_RX_AGNCD_ERR);
308f7df02e7SDavid van Moolenbroek 	lan8710a_reg_write(CPSW_STAT_RX_AGNCD_ERR, val);
309f7df02e7SDavid van Moolenbroek 	netdriver_stat_ierror(val);
310f7df02e7SDavid van Moolenbroek 
311f7df02e7SDavid van Moolenbroek 	val = lan8710a_reg_read(CPSW_STAT_RX_OVERSIZE);
312f7df02e7SDavid van Moolenbroek 	lan8710a_reg_write(CPSW_STAT_RX_OVERSIZE, val);
313f7df02e7SDavid van Moolenbroek 	netdriver_stat_ierror(val);
314f7df02e7SDavid van Moolenbroek 
315f7df02e7SDavid van Moolenbroek 	val = lan8710a_reg_read(CPSW_STAT_COLLISIONS);
316f7df02e7SDavid van Moolenbroek 	lan8710a_reg_write(CPSW_STAT_COLLISIONS, val);
317f7df02e7SDavid van Moolenbroek 	netdriver_stat_coll(val);
318f7df02e7SDavid van Moolenbroek }
319f7df02e7SDavid van Moolenbroek 
320f7df02e7SDavid van Moolenbroek /*============================================================================*
321f7df02e7SDavid van Moolenbroek  *				lan8710a_tick				      *
322f7df02e7SDavid van Moolenbroek  *============================================================================*/
323f7df02e7SDavid van Moolenbroek static void
lan8710a_tick(void)324f7df02e7SDavid van Moolenbroek lan8710a_tick(void)
325f7df02e7SDavid van Moolenbroek {
326f7df02e7SDavid van Moolenbroek 
327f7df02e7SDavid van Moolenbroek 	/* Update statistics. */
328f7df02e7SDavid van Moolenbroek 	lan8710a_update_stats();
329433d6423SLionel Sambuc }
330433d6423SLionel Sambuc 
331433d6423SLionel Sambuc /*============================================================================*
332433d6423SLionel Sambuc  *				lan8710a_stop				      *
333433d6423SLionel Sambuc  *============================================================================*/
334433d6423SLionel Sambuc static void
lan8710a_stop(void)335433d6423SLionel Sambuc lan8710a_stop(void)
336433d6423SLionel Sambuc {
337433d6423SLionel Sambuc 	/* Reset hardware. */
338433d6423SLionel Sambuc 	lan8710a_reset_hw();
339433d6423SLionel Sambuc }
340433d6423SLionel Sambuc 
341433d6423SLionel Sambuc /*============================================================================*
342433d6423SLionel Sambuc  *				lan8710a_dma_config_tx			      *
343433d6423SLionel Sambuc  *============================================================================*/
344433d6423SLionel Sambuc static void
lan8710a_dma_config_tx(u8_t desc_idx)3453c8950ccSBen Gras lan8710a_dma_config_tx(u8_t desc_idx)
346433d6423SLionel Sambuc {
347433d6423SLionel Sambuc 	phys_bytes phys_addr;
348433d6423SLionel Sambuc 	int i;
349433d6423SLionel Sambuc 	for (i = 0; i < TX_DMA_CHANNELS; ++i) {
350433d6423SLionel Sambuc 		if (!lan8710a_reg_read(CPDMA_STRAM_TX_HDP(i))) break;
351433d6423SLionel Sambuc 	}
352433d6423SLionel Sambuc 	if (i == TX_DMA_CHANNELS) {
353433d6423SLionel Sambuc 		panic("There are no free TX DMA channels.");
354433d6423SLionel Sambuc 	}
355433d6423SLionel Sambuc 
356433d6423SLionel Sambuc 	/* Enabling only one channel Tx interrupt */
357433d6423SLionel Sambuc 	lan8710a_reg_write(CPDMA_TX_INTMASK_SET, 1 << i);
358433d6423SLionel Sambuc 	/* Routing only one channel Tx int to TX_PULSE signal */
359433d6423SLionel Sambuc 	lan8710a_reg_write(CPSW_WR_C0_TX_EN, 1 << i);
360433d6423SLionel Sambuc 
361433d6423SLionel Sambuc 	/* Setting HDP */
362433d6423SLionel Sambuc 	phys_addr = lan8710a_state.tx_desc_phy +
363433d6423SLionel Sambuc 					(desc_idx * sizeof(lan8710a_desc_t));
364433d6423SLionel Sambuc 	lan8710a_reg_write(CPDMA_STRAM_TX_HDP(i), (u32_t)phys_addr);
365433d6423SLionel Sambuc }
366433d6423SLionel Sambuc 
367433d6423SLionel Sambuc /*============================================================================*
368433d6423SLionel Sambuc  *				lan8710a_dma_reset_init			      *
369433d6423SLionel Sambuc  *============================================================================*/
370433d6423SLionel Sambuc static void
lan8710a_dma_reset_init(void)371433d6423SLionel Sambuc lan8710a_dma_reset_init(void)
372433d6423SLionel Sambuc {
373433d6423SLionel Sambuc 	int i;
374433d6423SLionel Sambuc 	lan8710a_reg_write(CPDMA_SOFT_RESET, SOFT_RESET);
375433d6423SLionel Sambuc 	while ((lan8710a_reg_read(CPDMA_SOFT_RESET) & SOFT_RESET));
376433d6423SLionel Sambuc 
377433d6423SLionel Sambuc 	/*
378433d6423SLionel Sambuc 	 * Initialize the HDPs (Header Description Pointers) and
379433d6423SLionel Sambuc 	 * CPs (Completion Pointers) to NULL.
380433d6423SLionel Sambuc 	 */
381433d6423SLionel Sambuc 	for (i = 0; i < DMA_MAX_CHANNELS; ++i) {
382433d6423SLionel Sambuc 		lan8710a_reg_write(CPDMA_STRAM_TX_HDP(i), 0);
383433d6423SLionel Sambuc 		lan8710a_reg_write(CPDMA_STRAM_RX_HDP(i), 0);
384433d6423SLionel Sambuc 		lan8710a_reg_write(CPDMA_STRAM_TX_CP(i), 0);
385433d6423SLionel Sambuc 		lan8710a_reg_write(CPDMA_STRAM_RX_CP(i), 0);
386433d6423SLionel Sambuc 	}
387433d6423SLionel Sambuc 
388433d6423SLionel Sambuc 	lan8710a_reg_write(CPDMA_RX_INTMASK_CLEAR, 0xFFFFFFFF);
389433d6423SLionel Sambuc 	lan8710a_reg_write(CPDMA_TX_INTMASK_CLEAR, 0xFFFFFFFF);
390433d6423SLionel Sambuc 
391433d6423SLionel Sambuc 	/* Configure the CPDMA controller. */
392433d6423SLionel Sambuc 	lan8710a_reg_set(CPDMA_RX_CONTROL, CPDMA_RX_EN); /* RX Enabled */
393433d6423SLionel Sambuc 	lan8710a_reg_set(CPDMA_TX_CONTROL, CPDMA_TX_EN); /* TX Enabled */
394433d6423SLionel Sambuc 
395433d6423SLionel Sambuc 	/* Enabling first channel Rx interrupt */
396433d6423SLionel Sambuc 	lan8710a_reg_set(CPDMA_RX_INTMASK_SET, CPDMA_FIRST_CHAN_INT);
397433d6423SLionel Sambuc 
398433d6423SLionel Sambuc 	/*
399433d6423SLionel Sambuc 	 * Writing the address of the first buffer descriptor in the queue
400433d6423SLionel Sambuc 	 * (nonzero value)to the channel�s head descriptor pointer in the
401433d6423SLionel Sambuc 	 * channel�s Rx DMA state.
402433d6423SLionel Sambuc 	 */
403433d6423SLionel Sambuc 	lan8710a_reg_write(CPDMA_STRAM_RX_HDP(0),
404433d6423SLionel Sambuc 			  (u32_t)lan8710a_state.rx_desc_phy);
405433d6423SLionel Sambuc 
406433d6423SLionel Sambuc 	lan8710a_state.rx_desc_idx = 0;
407433d6423SLionel Sambuc 	lan8710a_state.tx_desc_idx = 0;
408433d6423SLionel Sambuc }
409433d6423SLionel Sambuc 
410433d6423SLionel Sambuc /*============================================================================*
411433d6423SLionel Sambuc  *				lan8710a_init_desc			      *
412433d6423SLionel Sambuc  *============================================================================*/
413433d6423SLionel Sambuc static void
lan8710a_init_desc(void)414433d6423SLionel Sambuc lan8710a_init_desc(void)
415433d6423SLionel Sambuc {
416433d6423SLionel Sambuc 	lan8710a_desc_t *p_rx_desc;
417433d6423SLionel Sambuc 	lan8710a_desc_t *p_tx_desc;
418433d6423SLionel Sambuc 	phys_bytes   buf_phys_addr;
419433d6423SLionel Sambuc 	u8_t i;
420433d6423SLionel Sambuc 
421433d6423SLionel Sambuc 	/* Attempt to allocate. */
422433d6423SLionel Sambuc 	if ((lan8710a_state.p_rx_buf = alloc_contig((LAN8710A_NUM_RX_DESC
423433d6423SLionel Sambuc 			* LAN8710A_IOBUF_SIZE), AC_ALIGN4K,
424433d6423SLionel Sambuc 			&buf_phys_addr)) == NULL) {
425433d6423SLionel Sambuc 		panic("failed to allocate RX buffers.");
426433d6423SLionel Sambuc 	}
427433d6423SLionel Sambuc 	for (i = 0; i < LAN8710A_NUM_RX_DESC; i++) {
428433d6423SLionel Sambuc 		p_rx_desc = &(lan8710a_state.rx_desc[i]);
429433d6423SLionel Sambuc 		memset(p_rx_desc, 0x0, sizeof(lan8710a_desc_t));
430433d6423SLionel Sambuc 		p_rx_desc->pkt_len_flags = LAN8710A_DESC_FLAG_OWN;
431433d6423SLionel Sambuc 		p_rx_desc->buffer_length_off = LAN8710A_IOBUF_SIZE;
432433d6423SLionel Sambuc 		p_rx_desc->buffer_pointer = (u32_t)(buf_phys_addr +
433433d6423SLionel Sambuc 						(i * LAN8710A_IOBUF_SIZE));
434433d6423SLionel Sambuc 
435433d6423SLionel Sambuc 		p_rx_desc->next_pointer =
436433d6423SLionel Sambuc 		   (u32_t)((i == (LAN8710A_NUM_RX_DESC - 1)) ?
437433d6423SLionel Sambuc 			   (lan8710a_state.rx_desc_phy) :
438433d6423SLionel Sambuc 			   (lan8710a_state.rx_desc_phy +
439433d6423SLionel Sambuc 			     ((i + 1) * sizeof(lan8710a_desc_t))));
440433d6423SLionel Sambuc 	}
441433d6423SLionel Sambuc 
442433d6423SLionel Sambuc 	/* Attempt to allocate. */
443433d6423SLionel Sambuc 	if ((lan8710a_state.p_tx_buf = alloc_contig((LAN8710A_NUM_TX_DESC
444433d6423SLionel Sambuc 			* LAN8710A_IOBUF_SIZE), AC_ALIGN4K,
445433d6423SLionel Sambuc 			&buf_phys_addr)) == NULL) {
446433d6423SLionel Sambuc 		panic("failed to allocate TX buffers");
447433d6423SLionel Sambuc 	}
448433d6423SLionel Sambuc 	for (i = 0; i < LAN8710A_NUM_TX_DESC; i++) {
449433d6423SLionel Sambuc 		p_tx_desc = &(lan8710a_state.tx_desc[i]);
450433d6423SLionel Sambuc 		memset(p_tx_desc, 0x0, sizeof(lan8710a_desc_t));
451433d6423SLionel Sambuc 		p_tx_desc->buffer_pointer = (u32_t)(buf_phys_addr +
452433d6423SLionel Sambuc 				(i * LAN8710A_IOBUF_SIZE));
453433d6423SLionel Sambuc 	}
454433d6423SLionel Sambuc 	lan8710a_state.rx_desc_idx = 0;
455433d6423SLionel Sambuc 	lan8710a_state.tx_desc_idx = 0;
456433d6423SLionel Sambuc }
457433d6423SLionel Sambuc 
458433d6423SLionel Sambuc /*============================================================================*
459433d6423SLionel Sambuc  *				lan8710a_init_hw			      *
460433d6423SLionel Sambuc  *============================================================================*/
461433d6423SLionel Sambuc static int
lan8710a_init_hw(netdriver_addr_t * addr,unsigned int instance)462f7df02e7SDavid van Moolenbroek lan8710a_init_hw(netdriver_addr_t * addr, unsigned int instance)
463433d6423SLionel Sambuc {
464433d6423SLionel Sambuc 	int r, i;
465433d6423SLionel Sambuc 
466433d6423SLionel Sambuc 	/*
467433d6423SLionel Sambuc 	 * Set the interrupt handler and policy. Do not automatically
468433d6423SLionel Sambuc 	 * re-enable interrupts. Return the IRQ line number on interrupts.
469433d6423SLionel Sambuc 	 */
470433d6423SLionel Sambuc 	lan8710a_state.irq_rx_hook = RX_INT;
471433d6423SLionel Sambuc 	if ((r = sys_irqsetpolicy(LAN8710A_RX_INTR, 0,
472433d6423SLionel Sambuc 					&lan8710a_state.irq_rx_hook)) != OK) {
473433d6423SLionel Sambuc 		panic("sys_irqsetpolicy failed: %d", r);
474433d6423SLionel Sambuc 	}
475433d6423SLionel Sambuc 	lan8710a_state.irq_tx_hook = TX_INT;
476433d6423SLionel Sambuc 	if ((r = sys_irqsetpolicy(LAN8710A_TX_INTR, 0,
477433d6423SLionel Sambuc 					&lan8710a_state.irq_tx_hook)) != OK) {
478433d6423SLionel Sambuc 		panic("sys_irqsetpolicy failed: %d", r);
479433d6423SLionel Sambuc 	}
480433d6423SLionel Sambuc 
481433d6423SLionel Sambuc 	/* Reset hardware. */
482433d6423SLionel Sambuc 	lan8710a_reset_hw();
483433d6423SLionel Sambuc 
484433d6423SLionel Sambuc 	/*
485433d6423SLionel Sambuc 	 * Select the Interface (GMII/RGMII/MII) Mode in the Control Module.
486433d6423SLionel Sambuc 	 * Port1 GMII/MII Mode, Port2 not used.
487433d6423SLionel Sambuc 	 */
488433d6423SLionel Sambuc 	lan8710a_reg_write(GMII_SEL, (GMII2_SEL_BIT1 | GMII2_SEL_BIT0));
489433d6423SLionel Sambuc 
490433d6423SLionel Sambuc 	/*
491433d6423SLionel Sambuc 	 * Configure pads (PIN muxing) as per the Interface Selected using the
492433d6423SLionel Sambuc 	 * appropriate pin muxing conf_xxx registers in the Control Module.
493433d6423SLionel Sambuc 	 *
494433d6423SLionel Sambuc 	 * CONF_MOD_SLEW_CTRL when 0 - Fast Mode, when 1 - Slow Mode
495433d6423SLionel Sambuc 	 * CONF_MOD_RX_ACTIVE when 0 - Only output, when 1 - Also input
496433d6423SLionel Sambuc 	 * CONF_MOD_PU_TYPESEL when 0 - Pull-down, when 1 - Pull-up
497433d6423SLionel Sambuc 	 * CONF_MOD_PUDEN when 0 Pull* enabled, when 1 Pull* disabled
498433d6423SLionel Sambuc 	 * CONF_MOD_MMODE_MII selects pin to work for MII interface
499433d6423SLionel Sambuc 	 */
500433d6423SLionel Sambuc 	lan8710a_reg_unset(CONF_MII1_COL, CONF_MOD_SLEW_CTRL);
501433d6423SLionel Sambuc 	lan8710a_reg_set(CONF_MII1_COL, CONF_MOD_RX_ACTIVE);
502433d6423SLionel Sambuc 	lan8710a_reg_set(CONF_MII1_COL, CONF_MOD_PU_TYPESEL);
503433d6423SLionel Sambuc 	lan8710a_reg_unset(CONF_MII1_COL, CONF_MOD_PUDEN);
504433d6423SLionel Sambuc 	lan8710a_reg_unset(CONF_MII1_COL, CONF_MOD_MMODE_MII);
505433d6423SLionel Sambuc 
506433d6423SLionel Sambuc 	lan8710a_reg_unset(CONF_MII1_CRS, CONF_MOD_SLEW_CTRL);
507433d6423SLionel Sambuc 	lan8710a_reg_set(CONF_MII1_CRS, CONF_MOD_RX_ACTIVE);
508433d6423SLionel Sambuc 	lan8710a_reg_set(CONF_MII1_CRS, CONF_MOD_PU_TYPESEL);
509433d6423SLionel Sambuc 	lan8710a_reg_unset(CONF_MII1_CRS, CONF_MOD_PUDEN);
510433d6423SLionel Sambuc 	lan8710a_reg_unset(CONF_MII1_CRS, CONF_MOD_MMODE_MII);
511433d6423SLionel Sambuc 
512433d6423SLionel Sambuc 	lan8710a_reg_unset(CONF_MII1_RX_ER, CONF_MOD_SLEW_CTRL);
513433d6423SLionel Sambuc 	lan8710a_reg_set(CONF_MII1_RX_ER, CONF_MOD_RX_ACTIVE);
514433d6423SLionel Sambuc 	lan8710a_reg_set(CONF_MII1_RX_ER, CONF_MOD_PU_TYPESEL);
515433d6423SLionel Sambuc 	lan8710a_reg_unset(CONF_MII1_RX_ER, CONF_MOD_PUDEN);
516433d6423SLionel Sambuc 	lan8710a_reg_unset(CONF_MII1_RX_ER, CONF_MOD_MMODE_MII);
517433d6423SLionel Sambuc 
518433d6423SLionel Sambuc 	lan8710a_reg_unset(CONF_MII1_TX_EN, CONF_MOD_SLEW_CTRL);
519433d6423SLionel Sambuc 	lan8710a_reg_unset(CONF_MII1_TX_EN, CONF_MOD_RX_ACTIVE);
520433d6423SLionel Sambuc 	lan8710a_reg_set(CONF_MII1_TX_EN, CONF_MOD_PUDEN);
521433d6423SLionel Sambuc 	lan8710a_reg_unset(CONF_MII1_TX_EN, CONF_MOD_MMODE_MII);
522433d6423SLionel Sambuc 
523433d6423SLionel Sambuc 	lan8710a_reg_unset(CONF_MII1_RX_DV, CONF_MOD_SLEW_CTRL);
524433d6423SLionel Sambuc 	lan8710a_reg_set(CONF_MII1_RX_DV, CONF_MOD_RX_ACTIVE);
525433d6423SLionel Sambuc 	lan8710a_reg_set(CONF_MII1_RX_DV, CONF_MOD_PU_TYPESEL);
526433d6423SLionel Sambuc 	lan8710a_reg_unset(CONF_MII1_RX_DV, CONF_MOD_PUDEN);
527433d6423SLionel Sambuc 	lan8710a_reg_unset(CONF_MII1_RX_DV, CONF_MOD_MMODE_MII);
528433d6423SLionel Sambuc 
529433d6423SLionel Sambuc 	lan8710a_reg_unset(CONF_MII1_TXD3, CONF_MOD_SLEW_CTRL);
530433d6423SLionel Sambuc 	lan8710a_reg_unset(CONF_MII1_TXD3, CONF_MOD_RX_ACTIVE);
531433d6423SLionel Sambuc 	lan8710a_reg_set(CONF_MII1_TXD3, CONF_MOD_PUDEN);
532433d6423SLionel Sambuc 	lan8710a_reg_unset(CONF_MII1_TXD3, CONF_MOD_MMODE_MII);
533433d6423SLionel Sambuc 
534433d6423SLionel Sambuc 	lan8710a_reg_unset(CONF_MII1_TXD2, CONF_MOD_SLEW_CTRL);
535433d6423SLionel Sambuc 	lan8710a_reg_unset(CONF_MII1_TXD2, CONF_MOD_RX_ACTIVE);
536433d6423SLionel Sambuc 	lan8710a_reg_set(CONF_MII1_TXD2, CONF_MOD_PUDEN);
537433d6423SLionel Sambuc 	lan8710a_reg_unset(CONF_MII1_TXD2, CONF_MOD_MMODE_MII);
538433d6423SLionel Sambuc 
539433d6423SLionel Sambuc 	lan8710a_reg_unset(CONF_MII1_TXD1, CONF_MOD_SLEW_CTRL);
540433d6423SLionel Sambuc 	lan8710a_reg_unset(CONF_MII1_TXD1, CONF_MOD_RX_ACTIVE);
541433d6423SLionel Sambuc 	lan8710a_reg_set(CONF_MII1_TXD1, CONF_MOD_PUDEN);
542433d6423SLionel Sambuc 	lan8710a_reg_unset(CONF_MII1_TXD1, CONF_MOD_MMODE_MII);
543433d6423SLionel Sambuc 
544433d6423SLionel Sambuc 	lan8710a_reg_unset(CONF_MII1_TXD0, CONF_MOD_SLEW_CTRL);
545433d6423SLionel Sambuc 	lan8710a_reg_unset(CONF_MII1_TXD0, CONF_MOD_RX_ACTIVE);
546433d6423SLionel Sambuc 	lan8710a_reg_set(CONF_MII1_TXD0, CONF_MOD_PUDEN);
547433d6423SLionel Sambuc 	lan8710a_reg_unset(CONF_MII1_TXD0, CONF_MOD_MMODE_MII);
548433d6423SLionel Sambuc 
549433d6423SLionel Sambuc 	lan8710a_reg_unset(CONF_MII1_TX_CLK, CONF_MOD_SLEW_CTRL);
550433d6423SLionel Sambuc 	lan8710a_reg_set(CONF_MII1_TX_CLK, CONF_MOD_RX_ACTIVE);
551433d6423SLionel Sambuc 	lan8710a_reg_set(CONF_MII1_TX_CLK, CONF_MOD_PUDEN);
552433d6423SLionel Sambuc 	lan8710a_reg_unset(CONF_MII1_TX_CLK, CONF_MOD_MMODE_MII);
553433d6423SLionel Sambuc 
554433d6423SLionel Sambuc 	lan8710a_reg_unset(CONF_MII1_RX_CLK, CONF_MOD_SLEW_CTRL);
555433d6423SLionel Sambuc 	lan8710a_reg_set(CONF_MII1_RX_CLK, CONF_MOD_RX_ACTIVE);
556433d6423SLionel Sambuc 	lan8710a_reg_set(CONF_MII1_RX_CLK, CONF_MOD_PUDEN);
557433d6423SLionel Sambuc 	lan8710a_reg_unset(CONF_MII1_RX_CLK, CONF_MOD_MMODE_MII);
558433d6423SLionel Sambuc 
559433d6423SLionel Sambuc 	lan8710a_reg_unset(CONF_MII1_RXD3, CONF_MOD_SLEW_CTRL);
560433d6423SLionel Sambuc 	lan8710a_reg_set(CONF_MII1_RXD3, CONF_MOD_RX_ACTIVE);
561433d6423SLionel Sambuc 	lan8710a_reg_set(CONF_MII1_RXD3, CONF_MOD_PU_TYPESEL);
562433d6423SLionel Sambuc 	lan8710a_reg_unset(CONF_MII1_RXD3, CONF_MOD_PUDEN);
563433d6423SLionel Sambuc 	lan8710a_reg_unset(CONF_MII1_RXD3, CONF_MOD_MMODE_MII);
564433d6423SLionel Sambuc 
565433d6423SLionel Sambuc 	lan8710a_reg_unset(CONF_MII1_RXD2, CONF_MOD_SLEW_CTRL);
566433d6423SLionel Sambuc 	lan8710a_reg_set(CONF_MII1_RXD2, CONF_MOD_RX_ACTIVE);
567433d6423SLionel Sambuc 	lan8710a_reg_set(CONF_MII1_RXD2, CONF_MOD_PU_TYPESEL);
568433d6423SLionel Sambuc 	lan8710a_reg_unset(CONF_MII1_RXD2, CONF_MOD_PUDEN);
569433d6423SLionel Sambuc 	lan8710a_reg_unset(CONF_MII1_RXD2, CONF_MOD_MMODE_MII);
570433d6423SLionel Sambuc 
571433d6423SLionel Sambuc 	lan8710a_reg_unset(CONF_MII1_RXD1, CONF_MOD_SLEW_CTRL);
572433d6423SLionel Sambuc 	lan8710a_reg_set(CONF_MII1_RXD1, CONF_MOD_RX_ACTIVE);
573433d6423SLionel Sambuc 	lan8710a_reg_set(CONF_MII1_RXD1, CONF_MOD_PU_TYPESEL);
574433d6423SLionel Sambuc 	lan8710a_reg_unset(CONF_MII1_RXD1, CONF_MOD_PUDEN);
575433d6423SLionel Sambuc 	lan8710a_reg_unset(CONF_MII1_RXD1, CONF_MOD_MMODE_MII);
576433d6423SLionel Sambuc 
577433d6423SLionel Sambuc 	lan8710a_reg_unset(CONF_MII1_RXD0, CONF_MOD_SLEW_CTRL);
578433d6423SLionel Sambuc 	lan8710a_reg_set(CONF_MII1_RXD0, CONF_MOD_RX_ACTIVE);
579433d6423SLionel Sambuc 	lan8710a_reg_set(CONF_MII1_RXD0, CONF_MOD_PU_TYPESEL);
580433d6423SLionel Sambuc 	lan8710a_reg_unset(CONF_MII1_RXD0, CONF_MOD_PUDEN);
581433d6423SLionel Sambuc 	lan8710a_reg_unset(CONF_MII1_RXD0, CONF_MOD_MMODE_MII);
582433d6423SLionel Sambuc 
583433d6423SLionel Sambuc 	lan8710a_reg_unset(CONF_MDIO, CONF_MOD_SLEW_CTRL);
584433d6423SLionel Sambuc 	lan8710a_reg_set(CONF_MDIO, CONF_MOD_RX_ACTIVE);
585433d6423SLionel Sambuc 	lan8710a_reg_set(CONF_MDIO, CONF_MOD_PU_TYPESEL);
586433d6423SLionel Sambuc 	lan8710a_reg_unset(CONF_MDIO, CONF_MOD_PUDEN);
587433d6423SLionel Sambuc 	lan8710a_reg_unset(CONF_MDIO, CONF_MOD_MMODE_MII);
588433d6423SLionel Sambuc 
589433d6423SLionel Sambuc 	lan8710a_reg_unset(CONF_MDC, CONF_MOD_SLEW_CTRL);
590433d6423SLionel Sambuc 	lan8710a_reg_unset(CONF_MDC, CONF_MOD_RX_ACTIVE);
591433d6423SLionel Sambuc 	lan8710a_reg_set(CONF_MDC, CONF_MOD_PUDEN);
592433d6423SLionel Sambuc 	lan8710a_reg_unset(CONF_MDC, CONF_MOD_MMODE_MII);
593433d6423SLionel Sambuc 
594433d6423SLionel Sambuc 	/* Apply soft reset to 3PSW Subsytem, CPSW_3G, CPGMAC_SL, and CPDMA. */
595433d6423SLionel Sambuc 	lan8710a_reg_write(CPSW_SS_SOFT_RESET, SOFT_RESET);
596433d6423SLionel Sambuc 	lan8710a_reg_write(CPSW_SL_SOFT_RESET(1), SOFT_RESET);
597433d6423SLionel Sambuc 	lan8710a_reg_write(CPSW_SL_SOFT_RESET(2), SOFT_RESET);
598433d6423SLionel Sambuc 
599433d6423SLionel Sambuc 	/* Wait for software resets completion */
600433d6423SLionel Sambuc 	while ((lan8710a_reg_read(CPSW_SS_SOFT_RESET) & SOFT_RESET) ||
601433d6423SLionel Sambuc 		(lan8710a_reg_read(CPSW_SL_SOFT_RESET(1)) & SOFT_RESET) ||
602433d6423SLionel Sambuc 		(lan8710a_reg_read(CPSW_SL_SOFT_RESET(2)) & SOFT_RESET));
603433d6423SLionel Sambuc 
604433d6423SLionel Sambuc 	/* Configure the Statistics Port Enable register. */
605433d6423SLionel Sambuc 	/* Enable port 0 and 1 statistics. */
606433d6423SLionel Sambuc 	lan8710a_reg_write(CPSW_SS_STAT_PORT_EN, (CPSW_P1_STAT_EN |
607433d6423SLionel Sambuc 							CPSW_P0_STAT_EN));
608433d6423SLionel Sambuc 
609433d6423SLionel Sambuc 	/*
610433d6423SLionel Sambuc 	 * Configure the ALE.
611433d6423SLionel Sambuc 	 * Enabling Ale.
612433d6423SLionel Sambuc 	 * All packets received on ports 1 are
613433d6423SLionel Sambuc 	 * sent to the host (only to the host).
614433d6423SLionel Sambuc 	 */
615433d6423SLionel Sambuc 	lan8710a_reg_write(CPSW_ALE_CONTROL, (CPSW_ALE_ENABLE |
616433d6423SLionel Sambuc 						CPSW_ALE_BYPASS));
617433d6423SLionel Sambuc 	/* Port 0 (host) in forwarding mode. */
618433d6423SLionel Sambuc 	lan8710a_reg_write(CPSW_ALE_PORTCTL0, CPSW_ALE_PORT_FWD);
619433d6423SLionel Sambuc 	/* Port 1 in forwarding mode. */
620433d6423SLionel Sambuc 	lan8710a_reg_write(CPSW_ALE_PORTCTL1, CPSW_ALE_PORT_FWD);
621433d6423SLionel Sambuc 
622433d6423SLionel Sambuc 	/*
623433d6423SLionel Sambuc 	 * Configure CPSW_SL Register
624433d6423SLionel Sambuc 	 * Full duplex mode.
625433d6423SLionel Sambuc 	 */
626433d6423SLionel Sambuc 	lan8710a_reg_write(CPSW_SL_MACCONTROL(1), CPSW_SL_FULLDUPLEX);
627433d6423SLionel Sambuc 
628433d6423SLionel Sambuc 	/* Initialize MDIO Protocol */
629433d6423SLionel Sambuc 	lan8710a_init_mdio();
630433d6423SLionel Sambuc 
631433d6423SLionel Sambuc 	/* Getting MAC Address */
632f7df02e7SDavid van Moolenbroek 	lan8710a_init_addr(addr, instance);
633433d6423SLionel Sambuc 
634433d6423SLionel Sambuc 	/* Initialize descriptors */
635433d6423SLionel Sambuc 	lan8710a_init_desc();
636433d6423SLionel Sambuc 
637433d6423SLionel Sambuc 	/* Reset and initialize CPDMA */
638433d6423SLionel Sambuc 	lan8710a_dma_reset_init();
639433d6423SLionel Sambuc 
640433d6423SLionel Sambuc 	/*
641433d6423SLionel Sambuc 	 * Configure the Interrupts.
642433d6423SLionel Sambuc 	 * Routing all channel Rx int to RX_PULSE signal.
643433d6423SLionel Sambuc 	 */
644433d6423SLionel Sambuc 	lan8710a_reg_set(CPSW_WR_C0_RX_EN, CPSW_FIRST_CHAN_INT);
645433d6423SLionel Sambuc 
646433d6423SLionel Sambuc 	/*
647433d6423SLionel Sambuc 	 * Enabling LAN8710A Auto-negotiation
648433d6423SLionel Sambuc 	 */
649433d6423SLionel Sambuc 	lan8710a_phy_write(LAN8710A_CTRL_REG, LAN8710A_AUTO_NEG);
650433d6423SLionel Sambuc 
651433d6423SLionel Sambuc 	/* Waiting for auto-negotiaion completion. */
652433d6423SLionel Sambuc 	for (i = 0; !(lan8710a_phy_read(LAN8710A_STATUS_REG) &
653433d6423SLionel Sambuc 					LAN8710A_AUTO_NEG_COMPL); ++i) {
654433d6423SLionel Sambuc 		if (i == 100) {
655433d6423SLionel Sambuc 			LAN8710A_DEBUG_PRINT(("Autonegotiation failed"));
656433d6423SLionel Sambuc 			break;
657433d6423SLionel Sambuc 		}
658*d4dd6511Srlfnb 		micro_delay(1666666);
659433d6423SLionel Sambuc 	}
660433d6423SLionel Sambuc 
661433d6423SLionel Sambuc 	/* GMII RX and TX release from reset. */
662433d6423SLionel Sambuc 	lan8710a_reg_set(CPSW_SL_MACCONTROL(1), CPSW_SL_GMII_EN);
663433d6423SLionel Sambuc 
664433d6423SLionel Sambuc 	/* Enable interrupts. */
665433d6423SLionel Sambuc 	lan8710a_enable_interrupt(RX_INT | TX_INT);
666433d6423SLionel Sambuc 
667433d6423SLionel Sambuc 	return TRUE;
668433d6423SLionel Sambuc }
669433d6423SLionel Sambuc 
670433d6423SLionel Sambuc /*============================================================================*
671433d6423SLionel Sambuc  *				lan8710a_init_mdio			      *
672433d6423SLionel Sambuc  *============================================================================*/
673433d6423SLionel Sambuc static void
lan8710a_init_mdio(void)674433d6423SLionel Sambuc lan8710a_init_mdio(void)
675433d6423SLionel Sambuc {
676433d6423SLionel Sambuc 	u16_t address = 0;
677433d6423SLionel Sambuc 	u32_t r;
678433d6423SLionel Sambuc 
679433d6423SLionel Sambuc 	/* Clearing MDIOCONTROL register */
680433d6423SLionel Sambuc 	lan8710a_reg_write(MDIOCONTROL, 0);
681433d6423SLionel Sambuc 	/* Configure the PREAMBLE and CLKDIV in the MDIO control register */
682433d6423SLionel Sambuc 	lan8710a_reg_unset(MDIOCONTROL, MDIO_PREAMBLE); /* CLKDIV default */
683433d6423SLionel Sambuc 	/* Enable sending MDIO frame preambles */
684433d6423SLionel Sambuc 	lan8710a_reg_set(MDIOCONTROL, (MDCLK_DIVIDER | MDIO_ENABLE));
685433d6423SLionel Sambuc 	/* Enable the MDIO module by setting the ENABLE bit in MDIOCONTROL */
686433d6423SLionel Sambuc 
687433d6423SLionel Sambuc 	while (!(r = lan8710a_reg_read(MDIOALIVE)));
688433d6423SLionel Sambuc 
689433d6423SLionel Sambuc 	/* Get PHY address */
690433d6423SLionel Sambuc 	while (r >>= 1) {
691433d6423SLionel Sambuc 		++address;
692433d6423SLionel Sambuc 	}
693433d6423SLionel Sambuc 	lan8710a_state.phy_address = address;
694433d6423SLionel Sambuc 
695433d6423SLionel Sambuc 	/* Setup appropiate address in MDIOUSERPHYSEL0 */
696433d6423SLionel Sambuc 	lan8710a_reg_set(MDIOUSERPHYSEL0, address);
697433d6423SLionel Sambuc }
698433d6423SLionel Sambuc 
699433d6423SLionel Sambuc /*============================================================================*
7005af3c256SDavid van Moolenbroek  *				lan8710a_send				      *
701433d6423SLionel Sambuc  *============================================================================*/
7025af3c256SDavid van Moolenbroek static int
lan8710a_send(struct netdriver_data * data,size_t size)7035af3c256SDavid van Moolenbroek lan8710a_send(struct netdriver_data * data, size_t size)
704433d6423SLionel Sambuc {
705433d6423SLionel Sambuc 	lan8710a_t *e = &lan8710a_state;
706433d6423SLionel Sambuc 	lan8710a_desc_t *p_tx_desc;
7075af3c256SDavid van Moolenbroek 	u8_t *buf;
708433d6423SLionel Sambuc 
709433d6423SLionel Sambuc 	/* setup descriptors */
710433d6423SLionel Sambuc 	p_tx_desc = &(e->tx_desc[e->tx_desc_idx]);
711433d6423SLionel Sambuc 
712433d6423SLionel Sambuc 	/*
7135af3c256SDavid van Moolenbroek 	 * Check if descriptor is available for host and suspend if not.
714433d6423SLionel Sambuc 	 */
7155af3c256SDavid van Moolenbroek 	if (LAN8710A_DESC_FLAG_OWN & p_tx_desc->pkt_len_flags)
7165af3c256SDavid van Moolenbroek 		return SUSPEND;
7175af3c256SDavid van Moolenbroek 
7185af3c256SDavid van Moolenbroek 	/* Drop packets that exceed the size of our transmission buffer. */
7195af3c256SDavid van Moolenbroek 	if (size > LAN8710A_IOBUF_SIZE) {
720f7df02e7SDavid van Moolenbroek 		printf("%s: dropping large packet (%zu)\n",
721f7df02e7SDavid van Moolenbroek 		    netdriver_name(), size);
7225af3c256SDavid van Moolenbroek 
7235af3c256SDavid van Moolenbroek 		return OK;
724433d6423SLionel Sambuc 	}
725433d6423SLionel Sambuc 
726433d6423SLionel Sambuc 	/* virtual address of buffer */
7275af3c256SDavid van Moolenbroek 	buf = e->p_tx_buf + e->tx_desc_idx * LAN8710A_IOBUF_SIZE;
728433d6423SLionel Sambuc 
7295af3c256SDavid van Moolenbroek 	netdriver_copyin(data, 0, buf, size);
730433d6423SLionel Sambuc 
731433d6423SLionel Sambuc 	/* set descriptor length */
7325af3c256SDavid van Moolenbroek 	p_tx_desc->buffer_length_off = size;
733433d6423SLionel Sambuc 	/* set flags */
734433d6423SLionel Sambuc 	p_tx_desc->pkt_len_flags = (LAN8710A_DESC_FLAG_OWN |
735433d6423SLionel Sambuc 					LAN8710A_DESC_FLAG_SOP |
736433d6423SLionel Sambuc 					LAN8710A_DESC_FLAG_EOP |
737433d6423SLionel Sambuc 					TX_DESC_TO_PORT1 |
738433d6423SLionel Sambuc 					TX_DESC_TO_PORT_EN);
7395af3c256SDavid van Moolenbroek 	p_tx_desc->pkt_len_flags |= size;
740433d6423SLionel Sambuc 
741433d6423SLionel Sambuc 	/* setup DMA transfer */
742433d6423SLionel Sambuc 	lan8710a_dma_config_tx(e->tx_desc_idx);
743433d6423SLionel Sambuc 
744433d6423SLionel Sambuc 	e->tx_desc_idx++;
7455af3c256SDavid van Moolenbroek 	if (LAN8710A_NUM_TX_DESC == e->tx_desc_idx)
746433d6423SLionel Sambuc 		e->tx_desc_idx = 0;
7475af3c256SDavid van Moolenbroek 
7485af3c256SDavid van Moolenbroek 	return OK;
749433d6423SLionel Sambuc }
750433d6423SLionel Sambuc 
751433d6423SLionel Sambuc /*============================================================================*
7525af3c256SDavid van Moolenbroek  *				lan8710a_recv				      *
753433d6423SLionel Sambuc  *============================================================================*/
7545af3c256SDavid van Moolenbroek static ssize_t
lan8710a_recv(struct netdriver_data * data,size_t max)7555af3c256SDavid van Moolenbroek lan8710a_recv(struct netdriver_data * data, size_t max)
756433d6423SLionel Sambuc {
757433d6423SLionel Sambuc 	lan8710a_t *e = &lan8710a_state;
758433d6423SLionel Sambuc 	lan8710a_desc_t *p_rx_desc;
759433d6423SLionel Sambuc 	u32_t flags;
7605af3c256SDavid van Moolenbroek 	u8_t *buf;
7615af3c256SDavid van Moolenbroek 	size_t off, size, chunk;
762433d6423SLionel Sambuc 
763433d6423SLionel Sambuc 	/*
764433d6423SLionel Sambuc 	 * Only handle one packet at a time.
765433d6423SLionel Sambuc 	 */
766433d6423SLionel Sambuc 	p_rx_desc = &(e->rx_desc[e->rx_desc_idx]);
767433d6423SLionel Sambuc 	/* find next OWN descriptor with SOP flag */
7685af3c256SDavid van Moolenbroek 	while ((0 == (LAN8710A_DESC_FLAG_SOP & p_rx_desc->pkt_len_flags)) &&
7695af3c256SDavid van Moolenbroek 	    (0 == (LAN8710A_DESC_FLAG_OWN & p_rx_desc->pkt_len_flags))) {
770433d6423SLionel Sambuc 		p_rx_desc->buffer_length_off = LAN8710A_IOBUF_SIZE;
771433d6423SLionel Sambuc 		/* set ownership of current descriptor to EMAC */
772433d6423SLionel Sambuc 		p_rx_desc->pkt_len_flags = LAN8710A_DESC_FLAG_OWN;
773433d6423SLionel Sambuc 
774433d6423SLionel Sambuc 		e->rx_desc_idx++;
775433d6423SLionel Sambuc 		if (LAN8710A_NUM_RX_DESC == e->rx_desc_idx)
776433d6423SLionel Sambuc 			e->rx_desc_idx = 0;
777433d6423SLionel Sambuc 		p_rx_desc = &(e->rx_desc[e->rx_desc_idx]);
778433d6423SLionel Sambuc 	}
7795af3c256SDavid van Moolenbroek 
780433d6423SLionel Sambuc 	if (0 == (LAN8710A_DESC_FLAG_SOP & p_rx_desc->pkt_len_flags)) {
781433d6423SLionel Sambuc 		/* SOP was not found */
7825af3c256SDavid van Moolenbroek 		return SUSPEND;
783433d6423SLionel Sambuc 	}
784433d6423SLionel Sambuc 
785433d6423SLionel Sambuc 	/*
7865af3c256SDavid van Moolenbroek 	 * Copy data from descriptors, from SOP to EOP inclusive.
7875af3c256SDavid van Moolenbroek 	 * TODO: make sure that the presence of a SOP slot implies the presence
7885af3c256SDavid van Moolenbroek 	 * of an EOP slot, because we are not checking for ownership below..
789433d6423SLionel Sambuc 	 */
7905af3c256SDavid van Moolenbroek 	size = 0;
7915af3c256SDavid van Moolenbroek 	off = 0;
792433d6423SLionel Sambuc 
7935af3c256SDavid van Moolenbroek 	for (;;) {
7945af3c256SDavid van Moolenbroek 		buf = e->p_rx_buf + e->rx_desc_idx * LAN8710A_IOBUF_SIZE + off;
7955af3c256SDavid van Moolenbroek 		chunk = p_rx_desc->buffer_length_off & 0xFFFF;
796433d6423SLionel Sambuc 
7975af3c256SDavid van Moolenbroek 		/* Truncate packets that are too large. */
7985af3c256SDavid van Moolenbroek 		if (chunk > max - size)
7995af3c256SDavid van Moolenbroek 			chunk = max - size;
800433d6423SLionel Sambuc 
8015af3c256SDavid van Moolenbroek 		if (chunk > 0) {
8025af3c256SDavid van Moolenbroek 			netdriver_copyout(data, size, buf, chunk);
8035af3c256SDavid van Moolenbroek 
8045af3c256SDavid van Moolenbroek 			size += chunk;
805433d6423SLionel Sambuc 		}
8065af3c256SDavid van Moolenbroek 
807433d6423SLionel Sambuc 		flags = p_rx_desc->pkt_len_flags;
8085af3c256SDavid van Moolenbroek 
8095af3c256SDavid van Moolenbroek 		/* Whole buffer move to the next descriptor */
810433d6423SLionel Sambuc 		p_rx_desc->buffer_length_off = LAN8710A_IOBUF_SIZE;
8115af3c256SDavid van Moolenbroek 		/* set ownership of current desc to EMAC */
812433d6423SLionel Sambuc 		p_rx_desc->pkt_len_flags = LAN8710A_DESC_FLAG_OWN;
813433d6423SLionel Sambuc 
814433d6423SLionel Sambuc 		e->rx_desc_idx++;
815433d6423SLionel Sambuc 		if (LAN8710A_NUM_RX_DESC == e->rx_desc_idx)
816433d6423SLionel Sambuc 			e->rx_desc_idx = 0;
817433d6423SLionel Sambuc 		p_rx_desc = &(e->rx_desc[e->rx_desc_idx]);
8185af3c256SDavid van Moolenbroek 
8195af3c256SDavid van Moolenbroek 		/* if EOP flag is set -> stop processing */
8205af3c256SDavid van Moolenbroek 		if (flags & LAN8710A_DESC_FLAG_EOP)
8215af3c256SDavid van Moolenbroek 			break;
822433d6423SLionel Sambuc 
823433d6423SLionel Sambuc 		/*
8245af3c256SDavid van Moolenbroek 		 * TODO: the upper 16 bits of buffer_length_off are used *only*
8255af3c256SDavid van Moolenbroek 		 * for descriptors *after* the first one; I'm retaining this
8265af3c256SDavid van Moolenbroek 		 * behavior because I don't have the chip's spec, but it may be
8275af3c256SDavid van Moolenbroek 		 * better to simplify/correct this behavior. --David
828433d6423SLionel Sambuc 		 */
8295af3c256SDavid van Moolenbroek 		off = p_rx_desc->buffer_length_off >> 16;
830433d6423SLionel Sambuc 	}
8315af3c256SDavid van Moolenbroek 
8325af3c256SDavid van Moolenbroek 	return size;
833433d6423SLionel Sambuc }
834433d6423SLionel Sambuc 
835433d6423SLionel Sambuc /*============================================================================*
836433d6423SLionel Sambuc  *				lan8710a_phy_write			      *
837433d6423SLionel Sambuc  *============================================================================*/
838433d6423SLionel Sambuc static void
lan8710a_phy_write(u32_t reg,u32_t value)8395af3c256SDavid van Moolenbroek lan8710a_phy_write(u32_t reg, u32_t value)
840433d6423SLionel Sambuc {
841433d6423SLionel Sambuc 	if (!(lan8710a_reg_read(MDIOUSERACCESS0) & MDIO_GO)) {
842433d6423SLionel Sambuc 		/* Clearing MDIOUSERACCESS0 register */
843433d6423SLionel Sambuc 		lan8710a_reg_write(MDIOUSERACCESS0, 0);
844433d6423SLionel Sambuc 		/* Setting proper values in MDIOUSERACCESS0 */
845433d6423SLionel Sambuc 		lan8710a_reg_set(MDIOUSERACCESS0, MDIO_WRITE);
846433d6423SLionel Sambuc 		lan8710a_reg_set(MDIOUSERACCESS0, reg << MDIO_REGADR);
847433d6423SLionel Sambuc 		lan8710a_reg_set(MDIOUSERACCESS0,
848433d6423SLionel Sambuc 				lan8710a_state.phy_address << MDIO_PHYADR);
849433d6423SLionel Sambuc 		/* Data written only 16 bits. */
8505af3c256SDavid van Moolenbroek 		lan8710a_reg_set(MDIOUSERACCESS0,
8515af3c256SDavid van Moolenbroek 		    (value & 0xFFFF) << MDIO_DATA);
852433d6423SLionel Sambuc 		lan8710a_reg_set(MDIOUSERACCESS0, MDIO_GO);
853433d6423SLionel Sambuc 
854433d6423SLionel Sambuc 		/* Waiting for writing completion */
855433d6423SLionel Sambuc 		while (lan8710a_reg_read(MDIOUSERACCESS0) & MDIO_GO);
856433d6423SLionel Sambuc 	}
857433d6423SLionel Sambuc }
858433d6423SLionel Sambuc 
859433d6423SLionel Sambuc /*============================================================================*
860433d6423SLionel Sambuc  *				lan8710a_phy_read			      *
861433d6423SLionel Sambuc  *============================================================================*/
862433d6423SLionel Sambuc static u32_t
lan8710a_phy_read(u32_t reg)8635af3c256SDavid van Moolenbroek lan8710a_phy_read(u32_t reg)
864433d6423SLionel Sambuc {
865433d6423SLionel Sambuc 	u32_t value = 0xFFFFFFFF;
866433d6423SLionel Sambuc 
867433d6423SLionel Sambuc 	if (!(lan8710a_reg_read(MDIOUSERACCESS0) & MDIO_GO)) {
868433d6423SLionel Sambuc 		/* Clearing MDIOUSERACCESS0 register */
869433d6423SLionel Sambuc 		lan8710a_reg_write(MDIOUSERACCESS0, 0);
870433d6423SLionel Sambuc 		/* Setting proper values in MDIOUSERACCESS0 */
871433d6423SLionel Sambuc 		lan8710a_reg_unset(MDIOUSERACCESS0, MDIO_WRITE);
872433d6423SLionel Sambuc 		/* Reg number must be 5 bit long */
873433d6423SLionel Sambuc 		lan8710a_reg_set(MDIOUSERACCESS0, (reg & 0x1F) << MDIO_REGADR);
874433d6423SLionel Sambuc 		/* Addr must be 5 bit long */
875433d6423SLionel Sambuc 		lan8710a_reg_set(MDIOUSERACCESS0,
876433d6423SLionel Sambuc 			(lan8710a_state.phy_address & 0x1F) << MDIO_PHYADR);
877433d6423SLionel Sambuc 		lan8710a_reg_set(MDIOUSERACCESS0, MDIO_GO);
878433d6423SLionel Sambuc 
879433d6423SLionel Sambuc 		/* Waiting for reading completion */
880433d6423SLionel Sambuc 		while ((lan8710a_reg_read(MDIOUSERACCESS0) & MDIO_GO)
881433d6423SLionel Sambuc 			&& !(lan8710a_reg_read(MDIOUSERACCESS0) & MDIO_ACK));
882433d6423SLionel Sambuc 
883433d6423SLionel Sambuc 		/* Reading data */
884433d6423SLionel Sambuc 		value = lan8710a_reg_read(MDIOUSERACCESS0) & 0xFFFF;
885433d6423SLionel Sambuc 	}
886433d6423SLionel Sambuc 	return value;
887433d6423SLionel Sambuc }
888433d6423SLionel Sambuc 
889433d6423SLionel Sambuc /*============================================================================*
890433d6423SLionel Sambuc  *				lan8710a_reset_hw			      *
891433d6423SLionel Sambuc  *============================================================================*/
892433d6423SLionel Sambuc static void
lan8710a_reset_hw(void)8935af3c256SDavid van Moolenbroek lan8710a_reset_hw(void)
894433d6423SLionel Sambuc {
895433d6423SLionel Sambuc 	/* Assert a Device Reset signal. */
896433d6423SLionel Sambuc 	lan8710a_phy_write(LAN8710A_CTRL_REG, LAN8710A_SOFT_RESET);
897433d6423SLionel Sambuc 
898433d6423SLionel Sambuc 	/* Waiting for reset completion. */
899433d6423SLionel Sambuc 	while (lan8710a_phy_read(LAN8710A_CTRL_REG) & LAN8710A_SOFT_RESET);
900433d6423SLionel Sambuc }
901433d6423SLionel Sambuc 
902433d6423SLionel Sambuc /*============================================================================*
903433d6423SLionel Sambuc  *				lan8710a_reg_read			      *
904433d6423SLionel Sambuc  *============================================================================*/
905433d6423SLionel Sambuc static u32_t
lan8710a_reg_read(volatile u32_t * reg)9065af3c256SDavid van Moolenbroek lan8710a_reg_read(volatile u32_t *reg)
907433d6423SLionel Sambuc {
908433d6423SLionel Sambuc 	u32_t value;
909433d6423SLionel Sambuc 
910433d6423SLionel Sambuc 	/* Read from memory mapped register. */
911433d6423SLionel Sambuc 	value = *reg;
912433d6423SLionel Sambuc 
913433d6423SLionel Sambuc 	/* Return the result. */
914433d6423SLionel Sambuc 	return value;
915433d6423SLionel Sambuc }
916433d6423SLionel Sambuc 
917433d6423SLionel Sambuc /*============================================================================*
918433d6423SLionel Sambuc  *				lan8710a_reg_write			      *
919433d6423SLionel Sambuc  *============================================================================*/
920433d6423SLionel Sambuc static void
lan8710a_reg_write(volatile u32_t * reg,u32_t value)9215af3c256SDavid van Moolenbroek lan8710a_reg_write(volatile u32_t *reg, u32_t value)
922433d6423SLionel Sambuc {
923433d6423SLionel Sambuc 	/* Write to memory mapped register. */
924433d6423SLionel Sambuc 	*reg = value;
925433d6423SLionel Sambuc }
926433d6423SLionel Sambuc 
927433d6423SLionel Sambuc /*============================================================================*
928433d6423SLionel Sambuc  *				lan8710a_reg_set			      *
929433d6423SLionel Sambuc  *============================================================================*/
930433d6423SLionel Sambuc static void
lan8710a_reg_set(volatile u32_t * reg,u32_t value)9315af3c256SDavid van Moolenbroek lan8710a_reg_set(volatile u32_t *reg, u32_t value)
932433d6423SLionel Sambuc {
933433d6423SLionel Sambuc 	u32_t data;
934433d6423SLionel Sambuc 
935433d6423SLionel Sambuc 	/* First read the current value. */
936433d6423SLionel Sambuc 	data = lan8710a_reg_read(reg);
937433d6423SLionel Sambuc 
938433d6423SLionel Sambuc 	/* Set value, and write back. */
939433d6423SLionel Sambuc 	lan8710a_reg_write(reg, data | value);
940433d6423SLionel Sambuc }
941433d6423SLionel Sambuc 
942433d6423SLionel Sambuc /*============================================================================*
943433d6423SLionel Sambuc  *				lan8710a_reg_unset			      *
944433d6423SLionel Sambuc  *============================================================================*/
945433d6423SLionel Sambuc static void
lan8710a_reg_unset(volatile u32_t * reg,u32_t value)9465af3c256SDavid van Moolenbroek lan8710a_reg_unset(volatile u32_t *reg, u32_t value)
947433d6423SLionel Sambuc {
948433d6423SLionel Sambuc 	u32_t data;
949433d6423SLionel Sambuc 
950433d6423SLionel Sambuc 	/* First read the current value. */
951433d6423SLionel Sambuc 	data = lan8710a_reg_read(reg);
952433d6423SLionel Sambuc 
953433d6423SLionel Sambuc 	/* Unset value, and write back. */
954433d6423SLionel Sambuc 	lan8710a_reg_write(reg, data & ~value);
955433d6423SLionel Sambuc }
956