1*83d290c5STom Rini // SPDX-License-Identifier: GPL-2.0+
2799e125cSJiandong Zheng /*
35c624b9eSSuji Velupillai  * Copyright 2014-2017 Broadcom.
4799e125cSJiandong Zheng  */
5799e125cSJiandong Zheng 
6799e125cSJiandong Zheng #ifdef BCM_GMAC_DEBUG
7799e125cSJiandong Zheng #ifndef DEBUG
8799e125cSJiandong Zheng #define DEBUG
9799e125cSJiandong Zheng #endif
10799e125cSJiandong Zheng #endif
11799e125cSJiandong Zheng 
12799e125cSJiandong Zheng #include <config.h>
13799e125cSJiandong Zheng #include <common.h>
14799e125cSJiandong Zheng #include <malloc.h>
15799e125cSJiandong Zheng #include <net.h>
16799e125cSJiandong Zheng #include <asm/io.h>
17799e125cSJiandong Zheng #include <phy.h>
18799e125cSJiandong Zheng 
19799e125cSJiandong Zheng #include "bcm-sf2-eth.h"
20799e125cSJiandong Zheng #include "bcm-sf2-eth-gmac.h"
21799e125cSJiandong Zheng 
22799e125cSJiandong Zheng #define SPINWAIT(exp, us) { \
23799e125cSJiandong Zheng 	uint countdown = (us) + 9; \
24799e125cSJiandong Zheng 	while ((exp) && (countdown >= 10)) {\
25799e125cSJiandong Zheng 		udelay(10); \
26799e125cSJiandong Zheng 		countdown -= 10; \
27799e125cSJiandong Zheng 	} \
28799e125cSJiandong Zheng }
29799e125cSJiandong Zheng 
305c624b9eSSuji Velupillai #define RX_BUF_SIZE_ALIGNED	ALIGN(RX_BUF_SIZE, ARCH_DMA_MINALIGN)
315c624b9eSSuji Velupillai #define TX_BUF_SIZE_ALIGNED	ALIGN(TX_BUF_SIZE, ARCH_DMA_MINALIGN)
325c624b9eSSuji Velupillai #define DESCP_SIZE_ALIGNED	ALIGN(sizeof(dma64dd_t), ARCH_DMA_MINALIGN)
335c624b9eSSuji Velupillai 
34799e125cSJiandong Zheng static int gmac_disable_dma(struct eth_dma *dma, int dir);
35799e125cSJiandong Zheng static int gmac_enable_dma(struct eth_dma *dma, int dir);
36799e125cSJiandong Zheng 
37799e125cSJiandong Zheng /* DMA Descriptor */
38799e125cSJiandong Zheng typedef struct {
39799e125cSJiandong Zheng 	/* misc control bits */
40799e125cSJiandong Zheng 	uint32_t	ctrl1;
41799e125cSJiandong Zheng 	/* buffer count and address extension */
42799e125cSJiandong Zheng 	uint32_t	ctrl2;
43799e125cSJiandong Zheng 	/* memory address of the date buffer, bits 31:0 */
44799e125cSJiandong Zheng 	uint32_t	addrlow;
45799e125cSJiandong Zheng 	/* memory address of the date buffer, bits 63:32 */
46799e125cSJiandong Zheng 	uint32_t	addrhigh;
47799e125cSJiandong Zheng } dma64dd_t;
48799e125cSJiandong Zheng 
49799e125cSJiandong Zheng uint32_t g_dmactrlflags;
50799e125cSJiandong Zheng 
dma_ctrlflags(uint32_t mask,uint32_t flags)51799e125cSJiandong Zheng static uint32_t dma_ctrlflags(uint32_t mask, uint32_t flags)
52799e125cSJiandong Zheng {
53799e125cSJiandong Zheng 	debug("%s enter\n", __func__);
54799e125cSJiandong Zheng 
55799e125cSJiandong Zheng 	g_dmactrlflags &= ~mask;
56799e125cSJiandong Zheng 	g_dmactrlflags |= flags;
57799e125cSJiandong Zheng 
58799e125cSJiandong Zheng 	/* If trying to enable parity, check if parity is actually supported */
59799e125cSJiandong Zheng 	if (g_dmactrlflags & DMA_CTRL_PEN) {
60799e125cSJiandong Zheng 		uint32_t control;
61799e125cSJiandong Zheng 
62799e125cSJiandong Zheng 		control = readl(GMAC0_DMA_TX_CTRL_ADDR);
63799e125cSJiandong Zheng 		writel(control | D64_XC_PD, GMAC0_DMA_TX_CTRL_ADDR);
64799e125cSJiandong Zheng 		if (readl(GMAC0_DMA_TX_CTRL_ADDR) & D64_XC_PD) {
65799e125cSJiandong Zheng 			/*
66799e125cSJiandong Zheng 			 * We *can* disable it, therefore it is supported;
67799e125cSJiandong Zheng 			 * restore control register
68799e125cSJiandong Zheng 			 */
69799e125cSJiandong Zheng 			writel(control, GMAC0_DMA_TX_CTRL_ADDR);
70799e125cSJiandong Zheng 		} else {
71799e125cSJiandong Zheng 			/* Not supported, don't allow it to be enabled */
72799e125cSJiandong Zheng 			g_dmactrlflags &= ~DMA_CTRL_PEN;
73799e125cSJiandong Zheng 		}
74799e125cSJiandong Zheng 	}
75799e125cSJiandong Zheng 
76799e125cSJiandong Zheng 	return g_dmactrlflags;
77799e125cSJiandong Zheng }
78799e125cSJiandong Zheng 
reg32_clear_bits(uint32_t reg,uint32_t value)79799e125cSJiandong Zheng static inline void reg32_clear_bits(uint32_t reg, uint32_t value)
80799e125cSJiandong Zheng {
81799e125cSJiandong Zheng 	uint32_t v = readl(reg);
82799e125cSJiandong Zheng 	v &= ~(value);
83799e125cSJiandong Zheng 	writel(v, reg);
84799e125cSJiandong Zheng }
85799e125cSJiandong Zheng 
reg32_set_bits(uint32_t reg,uint32_t value)86799e125cSJiandong Zheng static inline void reg32_set_bits(uint32_t reg, uint32_t value)
87799e125cSJiandong Zheng {
88799e125cSJiandong Zheng 	uint32_t v = readl(reg);
89799e125cSJiandong Zheng 	v |= value;
90799e125cSJiandong Zheng 	writel(v, reg);
91799e125cSJiandong Zheng }
92799e125cSJiandong Zheng 
93799e125cSJiandong Zheng #ifdef BCM_GMAC_DEBUG
dma_tx_dump(struct eth_dma * dma)94799e125cSJiandong Zheng static void dma_tx_dump(struct eth_dma *dma)
95799e125cSJiandong Zheng {
96799e125cSJiandong Zheng 	dma64dd_t *descp = NULL;
97799e125cSJiandong Zheng 	uint8_t *bufp;
98799e125cSJiandong Zheng 	int i;
99799e125cSJiandong Zheng 
100799e125cSJiandong Zheng 	printf("TX DMA Register:\n");
101799e125cSJiandong Zheng 	printf("control:0x%x; ptr:0x%x; addrl:0x%x; addrh:0x%x; stat0:0x%x, stat1:0x%x\n",
102799e125cSJiandong Zheng 	       readl(GMAC0_DMA_TX_CTRL_ADDR),
103799e125cSJiandong Zheng 	       readl(GMAC0_DMA_TX_PTR_ADDR),
104799e125cSJiandong Zheng 	       readl(GMAC0_DMA_TX_ADDR_LOW_ADDR),
105799e125cSJiandong Zheng 	       readl(GMAC0_DMA_TX_ADDR_HIGH_ADDR),
106799e125cSJiandong Zheng 	       readl(GMAC0_DMA_TX_STATUS0_ADDR),
107799e125cSJiandong Zheng 	       readl(GMAC0_DMA_TX_STATUS1_ADDR));
108799e125cSJiandong Zheng 
109799e125cSJiandong Zheng 	printf("TX Descriptors:\n");
110799e125cSJiandong Zheng 	for (i = 0; i < TX_BUF_NUM; i++) {
111799e125cSJiandong Zheng 		descp = (dma64dd_t *)(dma->tx_desc_aligned) + i;
112799e125cSJiandong Zheng 		printf("ctrl1:0x%08x; ctrl2:0x%08x; addr:0x%x 0x%08x\n",
113799e125cSJiandong Zheng 		       descp->ctrl1, descp->ctrl2,
114799e125cSJiandong Zheng 		       descp->addrhigh, descp->addrlow);
115799e125cSJiandong Zheng 	}
116799e125cSJiandong Zheng 
117799e125cSJiandong Zheng 	printf("TX Buffers:\n");
118799e125cSJiandong Zheng 	/* Initialize TX DMA descriptor table */
119799e125cSJiandong Zheng 	for (i = 0; i < TX_BUF_NUM; i++) {
1205c624b9eSSuji Velupillai 		bufp = (uint8_t *)(dma->tx_buf + i * TX_BUF_SIZE_ALIGNED);
121799e125cSJiandong Zheng 		printf("buf%d:0x%x; ", i, (uint32_t)bufp);
122799e125cSJiandong Zheng 	}
123799e125cSJiandong Zheng 	printf("\n");
124799e125cSJiandong Zheng }
125799e125cSJiandong Zheng 
dma_rx_dump(struct eth_dma * dma)126799e125cSJiandong Zheng static void dma_rx_dump(struct eth_dma *dma)
127799e125cSJiandong Zheng {
128799e125cSJiandong Zheng 	dma64dd_t *descp = NULL;
129799e125cSJiandong Zheng 	uint8_t *bufp;
130799e125cSJiandong Zheng 	int i;
131799e125cSJiandong Zheng 
132799e125cSJiandong Zheng 	printf("RX DMA Register:\n");
133799e125cSJiandong Zheng 	printf("control:0x%x; ptr:0x%x; addrl:0x%x; addrh:0x%x; stat0:0x%x, stat1:0x%x\n",
134799e125cSJiandong Zheng 	       readl(GMAC0_DMA_RX_CTRL_ADDR),
135799e125cSJiandong Zheng 	       readl(GMAC0_DMA_RX_PTR_ADDR),
136799e125cSJiandong Zheng 	       readl(GMAC0_DMA_RX_ADDR_LOW_ADDR),
137799e125cSJiandong Zheng 	       readl(GMAC0_DMA_RX_ADDR_HIGH_ADDR),
138799e125cSJiandong Zheng 	       readl(GMAC0_DMA_RX_STATUS0_ADDR),
139799e125cSJiandong Zheng 	       readl(GMAC0_DMA_RX_STATUS1_ADDR));
140799e125cSJiandong Zheng 
141799e125cSJiandong Zheng 	printf("RX Descriptors:\n");
142799e125cSJiandong Zheng 	for (i = 0; i < RX_BUF_NUM; i++) {
143799e125cSJiandong Zheng 		descp = (dma64dd_t *)(dma->rx_desc_aligned) + i;
144799e125cSJiandong Zheng 		printf("ctrl1:0x%08x; ctrl2:0x%08x; addr:0x%x 0x%08x\n",
145799e125cSJiandong Zheng 		       descp->ctrl1, descp->ctrl2,
146799e125cSJiandong Zheng 		       descp->addrhigh, descp->addrlow);
147799e125cSJiandong Zheng 	}
148799e125cSJiandong Zheng 
149799e125cSJiandong Zheng 	printf("RX Buffers:\n");
150799e125cSJiandong Zheng 	for (i = 0; i < RX_BUF_NUM; i++) {
1515c624b9eSSuji Velupillai 		bufp = dma->rx_buf + i * RX_BUF_SIZE_ALIGNED;
152799e125cSJiandong Zheng 		printf("buf%d:0x%x; ", i, (uint32_t)bufp);
153799e125cSJiandong Zheng 	}
154799e125cSJiandong Zheng 	printf("\n");
155799e125cSJiandong Zheng }
156799e125cSJiandong Zheng #endif
157799e125cSJiandong Zheng 
dma_tx_init(struct eth_dma * dma)158799e125cSJiandong Zheng static int dma_tx_init(struct eth_dma *dma)
159799e125cSJiandong Zheng {
160799e125cSJiandong Zheng 	dma64dd_t *descp = NULL;
161799e125cSJiandong Zheng 	uint8_t *bufp;
162799e125cSJiandong Zheng 	int i;
163799e125cSJiandong Zheng 	uint32_t ctrl;
164799e125cSJiandong Zheng 
165799e125cSJiandong Zheng 	debug("%s enter\n", __func__);
166799e125cSJiandong Zheng 
167799e125cSJiandong Zheng 	/* clear descriptor memory */
168799e125cSJiandong Zheng 	memset((void *)(dma->tx_desc_aligned), 0,
1695c624b9eSSuji Velupillai 	       TX_BUF_NUM * DESCP_SIZE_ALIGNED);
1705c624b9eSSuji Velupillai 	memset(dma->tx_buf, 0, TX_BUF_NUM * TX_BUF_SIZE_ALIGNED);
171799e125cSJiandong Zheng 
172799e125cSJiandong Zheng 	/* Initialize TX DMA descriptor table */
173799e125cSJiandong Zheng 	for (i = 0; i < TX_BUF_NUM; i++) {
174799e125cSJiandong Zheng 		descp = (dma64dd_t *)(dma->tx_desc_aligned) + i;
1755c624b9eSSuji Velupillai 		bufp = dma->tx_buf + i * TX_BUF_SIZE_ALIGNED;
176799e125cSJiandong Zheng 		/* clear buffer memory */
1775c624b9eSSuji Velupillai 		memset((void *)bufp, 0, TX_BUF_SIZE_ALIGNED);
178799e125cSJiandong Zheng 
179799e125cSJiandong Zheng 		ctrl = 0;
180799e125cSJiandong Zheng 		/* if last descr set endOfTable */
181799e125cSJiandong Zheng 		if (i == (TX_BUF_NUM-1))
182799e125cSJiandong Zheng 			ctrl = D64_CTRL1_EOT;
183799e125cSJiandong Zheng 		descp->ctrl1 = ctrl;
184799e125cSJiandong Zheng 		descp->ctrl2 = 0;
185799e125cSJiandong Zheng 		descp->addrlow = (uint32_t)bufp;
186799e125cSJiandong Zheng 		descp->addrhigh = 0;
187799e125cSJiandong Zheng 	}
188799e125cSJiandong Zheng 
189799e125cSJiandong Zheng 	/* flush descriptor and buffer */
190799e125cSJiandong Zheng 	descp = dma->tx_desc_aligned;
191799e125cSJiandong Zheng 	bufp = dma->tx_buf;
192799e125cSJiandong Zheng 	flush_dcache_range((unsigned long)descp,
1935c624b9eSSuji Velupillai 			   (unsigned long)descp +
1945c624b9eSSuji Velupillai 			   DESCP_SIZE_ALIGNED * TX_BUF_NUM);
1955c624b9eSSuji Velupillai 	flush_dcache_range((unsigned long)bufp,
1965c624b9eSSuji Velupillai 			   (unsigned long)bufp +
1975c624b9eSSuji Velupillai 			   TX_BUF_SIZE_ALIGNED * TX_BUF_NUM);
198799e125cSJiandong Zheng 
199799e125cSJiandong Zheng 	/* initialize the DMA channel */
200799e125cSJiandong Zheng 	writel((uint32_t)(dma->tx_desc_aligned), GMAC0_DMA_TX_ADDR_LOW_ADDR);
201799e125cSJiandong Zheng 	writel(0, GMAC0_DMA_TX_ADDR_HIGH_ADDR);
202799e125cSJiandong Zheng 
203799e125cSJiandong Zheng 	/* now update the dma last descriptor */
204799e125cSJiandong Zheng 	writel(((uint32_t)(dma->tx_desc_aligned)) & D64_XP_LD_MASK,
205799e125cSJiandong Zheng 	       GMAC0_DMA_TX_PTR_ADDR);
206799e125cSJiandong Zheng 
207799e125cSJiandong Zheng 	return 0;
208799e125cSJiandong Zheng }
209799e125cSJiandong Zheng 
dma_rx_init(struct eth_dma * dma)210799e125cSJiandong Zheng static int dma_rx_init(struct eth_dma *dma)
211799e125cSJiandong Zheng {
212799e125cSJiandong Zheng 	uint32_t last_desc;
213799e125cSJiandong Zheng 	dma64dd_t *descp = NULL;
214799e125cSJiandong Zheng 	uint8_t *bufp;
215799e125cSJiandong Zheng 	uint32_t ctrl;
216799e125cSJiandong Zheng 	int i;
217799e125cSJiandong Zheng 
218799e125cSJiandong Zheng 	debug("%s enter\n", __func__);
219799e125cSJiandong Zheng 
220799e125cSJiandong Zheng 	/* clear descriptor memory */
221799e125cSJiandong Zheng 	memset((void *)(dma->rx_desc_aligned), 0,
2225c624b9eSSuji Velupillai 	       RX_BUF_NUM * DESCP_SIZE_ALIGNED);
223799e125cSJiandong Zheng 	/* clear buffer memory */
2245c624b9eSSuji Velupillai 	memset(dma->rx_buf, 0, RX_BUF_NUM * RX_BUF_SIZE_ALIGNED);
225799e125cSJiandong Zheng 
226799e125cSJiandong Zheng 	/* Initialize RX DMA descriptor table */
227799e125cSJiandong Zheng 	for (i = 0; i < RX_BUF_NUM; i++) {
228799e125cSJiandong Zheng 		descp = (dma64dd_t *)(dma->rx_desc_aligned) + i;
2295c624b9eSSuji Velupillai 		bufp = dma->rx_buf + i * RX_BUF_SIZE_ALIGNED;
230799e125cSJiandong Zheng 		ctrl = 0;
231799e125cSJiandong Zheng 		/* if last descr set endOfTable */
232799e125cSJiandong Zheng 		if (i == (RX_BUF_NUM - 1))
233799e125cSJiandong Zheng 			ctrl = D64_CTRL1_EOT;
234799e125cSJiandong Zheng 		descp->ctrl1 = ctrl;
2355c624b9eSSuji Velupillai 		descp->ctrl2 = RX_BUF_SIZE_ALIGNED;
236799e125cSJiandong Zheng 		descp->addrlow = (uint32_t)bufp;
237799e125cSJiandong Zheng 		descp->addrhigh = 0;
238799e125cSJiandong Zheng 
239799e125cSJiandong Zheng 		last_desc = ((uint32_t)(descp) & D64_XP_LD_MASK)
240799e125cSJiandong Zheng 				+ sizeof(dma64dd_t);
241799e125cSJiandong Zheng 	}
242799e125cSJiandong Zheng 
243799e125cSJiandong Zheng 	descp = dma->rx_desc_aligned;
244799e125cSJiandong Zheng 	bufp = dma->rx_buf;
245799e125cSJiandong Zheng 	/* flush descriptor and buffer */
246799e125cSJiandong Zheng 	flush_dcache_range((unsigned long)descp,
2475c624b9eSSuji Velupillai 			   (unsigned long)descp +
2485c624b9eSSuji Velupillai 			   DESCP_SIZE_ALIGNED * RX_BUF_NUM);
249799e125cSJiandong Zheng 	flush_dcache_range((unsigned long)(bufp),
2505c624b9eSSuji Velupillai 			   (unsigned long)bufp +
2515c624b9eSSuji Velupillai 			   RX_BUF_SIZE_ALIGNED * RX_BUF_NUM);
252799e125cSJiandong Zheng 
253799e125cSJiandong Zheng 	/* initailize the DMA channel */
254799e125cSJiandong Zheng 	writel((uint32_t)descp, GMAC0_DMA_RX_ADDR_LOW_ADDR);
255799e125cSJiandong Zheng 	writel(0, GMAC0_DMA_RX_ADDR_HIGH_ADDR);
256799e125cSJiandong Zheng 
257799e125cSJiandong Zheng 	/* now update the dma last descriptor */
258799e125cSJiandong Zheng 	writel(last_desc, GMAC0_DMA_RX_PTR_ADDR);
259799e125cSJiandong Zheng 
260799e125cSJiandong Zheng 	return 0;
261799e125cSJiandong Zheng }
262799e125cSJiandong Zheng 
dma_init(struct eth_dma * dma)263799e125cSJiandong Zheng static int dma_init(struct eth_dma *dma)
264799e125cSJiandong Zheng {
265799e125cSJiandong Zheng 	debug(" %s enter\n", __func__);
266799e125cSJiandong Zheng 
267799e125cSJiandong Zheng 	/*
268799e125cSJiandong Zheng 	 * Default flags: For backwards compatibility both
269799e125cSJiandong Zheng 	 * Rx Overflow Continue and Parity are DISABLED.
270799e125cSJiandong Zheng 	 */
271799e125cSJiandong Zheng 	dma_ctrlflags(DMA_CTRL_ROC | DMA_CTRL_PEN, 0);
272799e125cSJiandong Zheng 
273799e125cSJiandong Zheng 	debug("rx burst len 0x%x\n",
274799e125cSJiandong Zheng 	      (readl(GMAC0_DMA_RX_CTRL_ADDR) & D64_RC_BL_MASK)
275799e125cSJiandong Zheng 	      >> D64_RC_BL_SHIFT);
276799e125cSJiandong Zheng 	debug("tx burst len 0x%x\n",
277799e125cSJiandong Zheng 	      (readl(GMAC0_DMA_TX_CTRL_ADDR) & D64_XC_BL_MASK)
278799e125cSJiandong Zheng 	      >> D64_XC_BL_SHIFT);
279799e125cSJiandong Zheng 
280799e125cSJiandong Zheng 	dma_tx_init(dma);
281799e125cSJiandong Zheng 	dma_rx_init(dma);
282799e125cSJiandong Zheng 
283799e125cSJiandong Zheng 	/* From end of chip_init() */
284799e125cSJiandong Zheng 	/* enable the overflow continue feature and disable parity */
285799e125cSJiandong Zheng 	dma_ctrlflags(DMA_CTRL_ROC | DMA_CTRL_PEN /* mask */,
286799e125cSJiandong Zheng 		      DMA_CTRL_ROC /* value */);
287799e125cSJiandong Zheng 
288799e125cSJiandong Zheng 	return 0;
289799e125cSJiandong Zheng }
290799e125cSJiandong Zheng 
dma_deinit(struct eth_dma * dma)291799e125cSJiandong Zheng static int dma_deinit(struct eth_dma *dma)
292799e125cSJiandong Zheng {
293799e125cSJiandong Zheng 	debug(" %s enter\n", __func__);
294799e125cSJiandong Zheng 
295799e125cSJiandong Zheng 	gmac_disable_dma(dma, MAC_DMA_RX);
296799e125cSJiandong Zheng 	gmac_disable_dma(dma, MAC_DMA_TX);
297799e125cSJiandong Zheng 
298799e125cSJiandong Zheng 	free(dma->tx_buf);
299799e125cSJiandong Zheng 	dma->tx_buf = NULL;
3005c624b9eSSuji Velupillai 	free(dma->tx_desc_aligned);
301799e125cSJiandong Zheng 	dma->tx_desc_aligned = NULL;
302799e125cSJiandong Zheng 
303799e125cSJiandong Zheng 	free(dma->rx_buf);
304799e125cSJiandong Zheng 	dma->rx_buf = NULL;
3055c624b9eSSuji Velupillai 	free(dma->rx_desc_aligned);
306799e125cSJiandong Zheng 	dma->rx_desc_aligned = NULL;
307799e125cSJiandong Zheng 
308799e125cSJiandong Zheng 	return 0;
309799e125cSJiandong Zheng }
310799e125cSJiandong Zheng 
gmac_tx_packet(struct eth_dma * dma,void * packet,int length)311799e125cSJiandong Zheng int gmac_tx_packet(struct eth_dma *dma, void *packet, int length)
312799e125cSJiandong Zheng {
3135c624b9eSSuji Velupillai 	uint8_t *bufp = dma->tx_buf + dma->cur_tx_index * TX_BUF_SIZE_ALIGNED;
314799e125cSJiandong Zheng 
315799e125cSJiandong Zheng 	/* kick off the dma */
316799e125cSJiandong Zheng 	size_t len = length;
317799e125cSJiandong Zheng 	int txout = dma->cur_tx_index;
318799e125cSJiandong Zheng 	uint32_t flags;
319799e125cSJiandong Zheng 	dma64dd_t *descp = NULL;
320799e125cSJiandong Zheng 	uint32_t ctrl;
321799e125cSJiandong Zheng 	uint32_t last_desc = (((uint32_t)dma->tx_desc_aligned) +
322799e125cSJiandong Zheng 			      sizeof(dma64dd_t)) & D64_XP_LD_MASK;
323799e125cSJiandong Zheng 	size_t buflen;
324799e125cSJiandong Zheng 
325799e125cSJiandong Zheng 	debug("%s enter\n", __func__);
326799e125cSJiandong Zheng 
327799e125cSJiandong Zheng 	/* load the buffer */
328799e125cSJiandong Zheng 	memcpy(bufp, packet, len);
329799e125cSJiandong Zheng 
330799e125cSJiandong Zheng 	/* Add 4 bytes for Ethernet FCS/CRC */
331799e125cSJiandong Zheng 	buflen = len + 4;
332799e125cSJiandong Zheng 
333799e125cSJiandong Zheng 	ctrl = (buflen & D64_CTRL2_BC_MASK);
334799e125cSJiandong Zheng 
335799e125cSJiandong Zheng 	/* the transmit will only be one frame or set SOF, EOF */
336799e125cSJiandong Zheng 	/* also set int on completion */
337799e125cSJiandong Zheng 	flags = D64_CTRL1_SOF | D64_CTRL1_IOC | D64_CTRL1_EOF;
338799e125cSJiandong Zheng 
339799e125cSJiandong Zheng 	/* txout points to the descriptor to uset */
340799e125cSJiandong Zheng 	/* if last descriptor then set EOT */
341799e125cSJiandong Zheng 	if (txout == (TX_BUF_NUM - 1)) {
342799e125cSJiandong Zheng 		flags |= D64_CTRL1_EOT;
343799e125cSJiandong Zheng 		last_desc = ((uint32_t)(dma->tx_desc_aligned)) & D64_XP_LD_MASK;
344799e125cSJiandong Zheng 	}
345799e125cSJiandong Zheng 
346799e125cSJiandong Zheng 	/* write the descriptor */
347799e125cSJiandong Zheng 	descp = ((dma64dd_t *)(dma->tx_desc_aligned)) + txout;
348799e125cSJiandong Zheng 	descp->addrlow = (uint32_t)bufp;
349799e125cSJiandong Zheng 	descp->addrhigh = 0;
350799e125cSJiandong Zheng 	descp->ctrl1 = flags;
351799e125cSJiandong Zheng 	descp->ctrl2 = ctrl;
352799e125cSJiandong Zheng 
353799e125cSJiandong Zheng 	/* flush descriptor and buffer */
3545c624b9eSSuji Velupillai 	flush_dcache_range((unsigned long)dma->tx_desc_aligned,
3555c624b9eSSuji Velupillai 			   (unsigned long)dma->tx_desc_aligned +
3565c624b9eSSuji Velupillai 			   DESCP_SIZE_ALIGNED * TX_BUF_NUM);
357799e125cSJiandong Zheng 	flush_dcache_range((unsigned long)bufp,
3585c624b9eSSuji Velupillai 			   (unsigned long)bufp + TX_BUF_SIZE_ALIGNED);
359799e125cSJiandong Zheng 
360799e125cSJiandong Zheng 	/* now update the dma last descriptor */
361799e125cSJiandong Zheng 	writel(last_desc, GMAC0_DMA_TX_PTR_ADDR);
362799e125cSJiandong Zheng 
363799e125cSJiandong Zheng 	/* tx dma should be enabled so packet should go out */
364799e125cSJiandong Zheng 
365799e125cSJiandong Zheng 	/* update txout */
366799e125cSJiandong Zheng 	dma->cur_tx_index = (txout + 1) & (TX_BUF_NUM - 1);
367799e125cSJiandong Zheng 
368799e125cSJiandong Zheng 	return 0;
369799e125cSJiandong Zheng }
370799e125cSJiandong Zheng 
gmac_check_tx_done(struct eth_dma * dma)371799e125cSJiandong Zheng bool gmac_check_tx_done(struct eth_dma *dma)
372799e125cSJiandong Zheng {
373799e125cSJiandong Zheng 	/* wait for tx to complete */
374799e125cSJiandong Zheng 	uint32_t intstatus;
375799e125cSJiandong Zheng 	bool xfrdone = false;
376799e125cSJiandong Zheng 
377799e125cSJiandong Zheng 	debug("%s enter\n", __func__);
378799e125cSJiandong Zheng 
379799e125cSJiandong Zheng 	intstatus = readl(GMAC0_INT_STATUS_ADDR);
380799e125cSJiandong Zheng 
381799e125cSJiandong Zheng 	debug("int(0x%x)\n", intstatus);
382799e125cSJiandong Zheng 	if (intstatus & (I_XI0 | I_XI1 | I_XI2 | I_XI3)) {
383799e125cSJiandong Zheng 		xfrdone = true;
384799e125cSJiandong Zheng 		/* clear the int bits */
385799e125cSJiandong Zheng 		intstatus &= ~(I_XI0 | I_XI1 | I_XI2 | I_XI3);
386799e125cSJiandong Zheng 		writel(intstatus, GMAC0_INT_STATUS_ADDR);
387799e125cSJiandong Zheng 	} else {
388799e125cSJiandong Zheng 		debug("Tx int(0x%x)\n", intstatus);
389799e125cSJiandong Zheng 	}
390799e125cSJiandong Zheng 
391799e125cSJiandong Zheng 	return xfrdone;
392799e125cSJiandong Zheng }
393799e125cSJiandong Zheng 
gmac_check_rx_done(struct eth_dma * dma,uint8_t * buf)394799e125cSJiandong Zheng int gmac_check_rx_done(struct eth_dma *dma, uint8_t *buf)
395799e125cSJiandong Zheng {
396799e125cSJiandong Zheng 	void *bufp, *datap;
397799e125cSJiandong Zheng 	size_t rcvlen = 0, buflen = 0;
398799e125cSJiandong Zheng 	uint32_t stat0 = 0, stat1 = 0;
399799e125cSJiandong Zheng 	uint32_t control, offset;
400799e125cSJiandong Zheng 	uint8_t statbuf[HWRXOFF*2];
401799e125cSJiandong Zheng 
402799e125cSJiandong Zheng 	int index, curr, active;
403799e125cSJiandong Zheng 	dma64dd_t *descp = NULL;
404799e125cSJiandong Zheng 
405799e125cSJiandong Zheng 	/* udelay(50); */
406799e125cSJiandong Zheng 
407799e125cSJiandong Zheng 	/*
408799e125cSJiandong Zheng 	 * this api will check if a packet has been received.
409799e125cSJiandong Zheng 	 * If so it will return the address of the buffer and current
410799e125cSJiandong Zheng 	 * descriptor index will be incremented to the
411799e125cSJiandong Zheng 	 * next descriptor. Once done with the frame the buffer should be
412799e125cSJiandong Zheng 	 * added back onto the descriptor and the lastdscr should be updated
413799e125cSJiandong Zheng 	 * to this descriptor.
414799e125cSJiandong Zheng 	 */
415799e125cSJiandong Zheng 	index = dma->cur_rx_index;
416799e125cSJiandong Zheng 	offset = (uint32_t)(dma->rx_desc_aligned);
417799e125cSJiandong Zheng 	stat0 = readl(GMAC0_DMA_RX_STATUS0_ADDR) & D64_RS0_CD_MASK;
418799e125cSJiandong Zheng 	stat1 = readl(GMAC0_DMA_RX_STATUS1_ADDR) & D64_RS0_CD_MASK;
419799e125cSJiandong Zheng 	curr = ((stat0 - offset) & D64_RS0_CD_MASK) / sizeof(dma64dd_t);
420799e125cSJiandong Zheng 	active = ((stat1 - offset) & D64_RS0_CD_MASK) / sizeof(dma64dd_t);
421799e125cSJiandong Zheng 
422799e125cSJiandong Zheng 	/* check if any frame */
423799e125cSJiandong Zheng 	if (index == curr)
424799e125cSJiandong Zheng 		return -1;
425799e125cSJiandong Zheng 
426799e125cSJiandong Zheng 	debug("received packet\n");
427799e125cSJiandong Zheng 	debug("expect(0x%x) curr(0x%x) active(0x%x)\n", index, curr, active);
428799e125cSJiandong Zheng 	/* remove warning */
429799e125cSJiandong Zheng 	if (index == active)
430799e125cSJiandong Zheng 		;
431799e125cSJiandong Zheng 
432799e125cSJiandong Zheng 	/* get the packet pointer that corresponds to the rx descriptor */
4335c624b9eSSuji Velupillai 	bufp = dma->rx_buf + index * RX_BUF_SIZE_ALIGNED;
434799e125cSJiandong Zheng 
435799e125cSJiandong Zheng 	descp = (dma64dd_t *)(dma->rx_desc_aligned) + index;
436799e125cSJiandong Zheng 	/* flush descriptor and buffer */
4375c624b9eSSuji Velupillai 	flush_dcache_range((unsigned long)dma->rx_desc_aligned,
4385c624b9eSSuji Velupillai 			   (unsigned long)dma->rx_desc_aligned +
4395c624b9eSSuji Velupillai 			   DESCP_SIZE_ALIGNED * RX_BUF_NUM);
440799e125cSJiandong Zheng 	flush_dcache_range((unsigned long)bufp,
4415c624b9eSSuji Velupillai 			   (unsigned long)bufp + RX_BUF_SIZE_ALIGNED);
442799e125cSJiandong Zheng 
443799e125cSJiandong Zheng 	buflen = (descp->ctrl2 & D64_CTRL2_BC_MASK);
444799e125cSJiandong Zheng 
445799e125cSJiandong Zheng 	stat0 = readl(GMAC0_DMA_RX_STATUS0_ADDR);
446799e125cSJiandong Zheng 	stat1 = readl(GMAC0_DMA_RX_STATUS1_ADDR);
447799e125cSJiandong Zheng 
448799e125cSJiandong Zheng 	debug("bufp(0x%x) index(0x%x) buflen(0x%x) stat0(0x%x) stat1(0x%x)\n",
449799e125cSJiandong Zheng 	      (uint32_t)bufp, index, buflen, stat0, stat1);
450799e125cSJiandong Zheng 
451799e125cSJiandong Zheng 	dma->cur_rx_index = (index + 1) & (RX_BUF_NUM - 1);
452799e125cSJiandong Zheng 
453799e125cSJiandong Zheng 	/* get buffer offset */
454799e125cSJiandong Zheng 	control = readl(GMAC0_DMA_RX_CTRL_ADDR);
455799e125cSJiandong Zheng 	offset = (control & D64_RC_RO_MASK) >> D64_RC_RO_SHIFT;
456799e125cSJiandong Zheng 	rcvlen = *(uint16_t *)bufp;
457799e125cSJiandong Zheng 
458799e125cSJiandong Zheng 	debug("Received %d bytes\n", rcvlen);
459799e125cSJiandong Zheng 	/* copy status into temp buf then copy data from rx buffer */
460799e125cSJiandong Zheng 	memcpy(statbuf, bufp, offset);
461799e125cSJiandong Zheng 	datap = (void *)((uint32_t)bufp + offset);
462799e125cSJiandong Zheng 	memcpy(buf, datap, rcvlen);
463799e125cSJiandong Zheng 
464799e125cSJiandong Zheng 	/* update descriptor that is being added back on ring */
4655c624b9eSSuji Velupillai 	descp->ctrl2 = RX_BUF_SIZE_ALIGNED;
466799e125cSJiandong Zheng 	descp->addrlow = (uint32_t)bufp;
467799e125cSJiandong Zheng 	descp->addrhigh = 0;
468799e125cSJiandong Zheng 	/* flush descriptor */
4695c624b9eSSuji Velupillai 	flush_dcache_range((unsigned long)dma->rx_desc_aligned,
4705c624b9eSSuji Velupillai 			   (unsigned long)dma->rx_desc_aligned +
4715c624b9eSSuji Velupillai 			   DESCP_SIZE_ALIGNED * RX_BUF_NUM);
472799e125cSJiandong Zheng 
473799e125cSJiandong Zheng 	/* set the lastdscr for the rx ring */
474799e125cSJiandong Zheng 	writel(((uint32_t)descp) & D64_XP_LD_MASK, GMAC0_DMA_RX_PTR_ADDR);
475799e125cSJiandong Zheng 
476799e125cSJiandong Zheng 	return (int)rcvlen;
477799e125cSJiandong Zheng }
478799e125cSJiandong Zheng 
gmac_disable_dma(struct eth_dma * dma,int dir)479799e125cSJiandong Zheng static int gmac_disable_dma(struct eth_dma *dma, int dir)
480799e125cSJiandong Zheng {
481799e125cSJiandong Zheng 	int status;
482799e125cSJiandong Zheng 
483799e125cSJiandong Zheng 	debug("%s enter\n", __func__);
484799e125cSJiandong Zheng 
485799e125cSJiandong Zheng 	if (dir == MAC_DMA_TX) {
486799e125cSJiandong Zheng 		/* address PR8249/PR7577 issue */
487799e125cSJiandong Zheng 		/* suspend tx DMA first */
488799e125cSJiandong Zheng 		writel(D64_XC_SE, GMAC0_DMA_TX_CTRL_ADDR);
489799e125cSJiandong Zheng 		SPINWAIT(((status = (readl(GMAC0_DMA_TX_STATUS0_ADDR) &
490799e125cSJiandong Zheng 				     D64_XS0_XS_MASK)) !=
491799e125cSJiandong Zheng 			  D64_XS0_XS_DISABLED) &&
492799e125cSJiandong Zheng 			 (status != D64_XS0_XS_IDLE) &&
493799e125cSJiandong Zheng 			 (status != D64_XS0_XS_STOPPED), 10000);
494799e125cSJiandong Zheng 
495799e125cSJiandong Zheng 		/*
496799e125cSJiandong Zheng 		 * PR2414 WAR: DMA engines are not disabled until
497799e125cSJiandong Zheng 		 * transfer finishes
498799e125cSJiandong Zheng 		 */
499799e125cSJiandong Zheng 		writel(0, GMAC0_DMA_TX_CTRL_ADDR);
500799e125cSJiandong Zheng 		SPINWAIT(((status = (readl(GMAC0_DMA_TX_STATUS0_ADDR) &
501799e125cSJiandong Zheng 				     D64_XS0_XS_MASK)) !=
502799e125cSJiandong Zheng 			  D64_XS0_XS_DISABLED), 10000);
503799e125cSJiandong Zheng 
504799e125cSJiandong Zheng 		/* wait for the last transaction to complete */
505799e125cSJiandong Zheng 		udelay(2);
506799e125cSJiandong Zheng 
507799e125cSJiandong Zheng 		status = (status == D64_XS0_XS_DISABLED);
508799e125cSJiandong Zheng 	} else {
509799e125cSJiandong Zheng 		/*
510799e125cSJiandong Zheng 		 * PR2414 WAR: DMA engines are not disabled until
511799e125cSJiandong Zheng 		 * transfer finishes
512799e125cSJiandong Zheng 		 */
513799e125cSJiandong Zheng 		writel(0, GMAC0_DMA_RX_CTRL_ADDR);
514799e125cSJiandong Zheng 		SPINWAIT(((status = (readl(GMAC0_DMA_RX_STATUS0_ADDR) &
515799e125cSJiandong Zheng 				     D64_RS0_RS_MASK)) !=
516799e125cSJiandong Zheng 			  D64_RS0_RS_DISABLED), 10000);
517799e125cSJiandong Zheng 
518799e125cSJiandong Zheng 		status = (status == D64_RS0_RS_DISABLED);
519799e125cSJiandong Zheng 	}
520799e125cSJiandong Zheng 
521799e125cSJiandong Zheng 	return status;
522799e125cSJiandong Zheng }
523799e125cSJiandong Zheng 
gmac_enable_dma(struct eth_dma * dma,int dir)524799e125cSJiandong Zheng static int gmac_enable_dma(struct eth_dma *dma, int dir)
525799e125cSJiandong Zheng {
526799e125cSJiandong Zheng 	uint32_t control;
527799e125cSJiandong Zheng 
528799e125cSJiandong Zheng 	debug("%s enter\n", __func__);
529799e125cSJiandong Zheng 
530799e125cSJiandong Zheng 	if (dir == MAC_DMA_TX) {
531799e125cSJiandong Zheng 		dma->cur_tx_index = 0;
532799e125cSJiandong Zheng 
533799e125cSJiandong Zheng 		/*
534799e125cSJiandong Zheng 		 * These bits 20:18 (burstLen) of control register can be
535799e125cSJiandong Zheng 		 * written but will take effect only if these bits are
536799e125cSJiandong Zheng 		 * valid. So this will not affect previous versions
537799e125cSJiandong Zheng 		 * of the DMA. They will continue to have those bits set to 0.
538799e125cSJiandong Zheng 		 */
539799e125cSJiandong Zheng 		control = readl(GMAC0_DMA_TX_CTRL_ADDR);
540799e125cSJiandong Zheng 
541799e125cSJiandong Zheng 		control |= D64_XC_XE;
542799e125cSJiandong Zheng 		if ((g_dmactrlflags & DMA_CTRL_PEN) == 0)
543799e125cSJiandong Zheng 			control |= D64_XC_PD;
544799e125cSJiandong Zheng 
545799e125cSJiandong Zheng 		writel(control, GMAC0_DMA_TX_CTRL_ADDR);
546799e125cSJiandong Zheng 
547799e125cSJiandong Zheng 		/* initailize the DMA channel */
548799e125cSJiandong Zheng 		writel((uint32_t)(dma->tx_desc_aligned),
549799e125cSJiandong Zheng 		       GMAC0_DMA_TX_ADDR_LOW_ADDR);
550799e125cSJiandong Zheng 		writel(0, GMAC0_DMA_TX_ADDR_HIGH_ADDR);
551799e125cSJiandong Zheng 	} else {
552799e125cSJiandong Zheng 		dma->cur_rx_index = 0;
553799e125cSJiandong Zheng 
554799e125cSJiandong Zheng 		control = (readl(GMAC0_DMA_RX_CTRL_ADDR) &
555799e125cSJiandong Zheng 			   D64_RC_AE) | D64_RC_RE;
556799e125cSJiandong Zheng 
557799e125cSJiandong Zheng 		if ((g_dmactrlflags & DMA_CTRL_PEN) == 0)
558799e125cSJiandong Zheng 			control |= D64_RC_PD;
559799e125cSJiandong Zheng 
560799e125cSJiandong Zheng 		if (g_dmactrlflags & DMA_CTRL_ROC)
561799e125cSJiandong Zheng 			control |= D64_RC_OC;
562799e125cSJiandong Zheng 
563799e125cSJiandong Zheng 		/*
564799e125cSJiandong Zheng 		 * These bits 20:18 (burstLen) of control register can be
565799e125cSJiandong Zheng 		 * written but will take effect only if these bits are
566799e125cSJiandong Zheng 		 * valid. So this will not affect previous versions
567799e125cSJiandong Zheng 		 * of the DMA. They will continue to have those bits set to 0.
568799e125cSJiandong Zheng 		 */
569799e125cSJiandong Zheng 		control &= ~D64_RC_BL_MASK;
570799e125cSJiandong Zheng 		/* Keep default Rx burstlen */
571799e125cSJiandong Zheng 		control |= readl(GMAC0_DMA_RX_CTRL_ADDR) & D64_RC_BL_MASK;
572799e125cSJiandong Zheng 		control |= HWRXOFF << D64_RC_RO_SHIFT;
573799e125cSJiandong Zheng 
574799e125cSJiandong Zheng 		writel(control, GMAC0_DMA_RX_CTRL_ADDR);
575799e125cSJiandong Zheng 
576799e125cSJiandong Zheng 		/*
577799e125cSJiandong Zheng 		 * the rx descriptor ring should have
578799e125cSJiandong Zheng 		 * the addresses set properly;
579799e125cSJiandong Zheng 		 * set the lastdscr for the rx ring
580799e125cSJiandong Zheng 		 */
581799e125cSJiandong Zheng 		writel(((uint32_t)(dma->rx_desc_aligned) +
5825c624b9eSSuji Velupillai 			(RX_BUF_NUM - 1) * RX_BUF_SIZE_ALIGNED) &
583799e125cSJiandong Zheng 		       D64_XP_LD_MASK, GMAC0_DMA_RX_PTR_ADDR);
584799e125cSJiandong Zheng 	}
585799e125cSJiandong Zheng 
586799e125cSJiandong Zheng 	return 0;
587799e125cSJiandong Zheng }
588799e125cSJiandong Zheng 
gmac_mii_busywait(unsigned int timeout)589799e125cSJiandong Zheng bool gmac_mii_busywait(unsigned int timeout)
590799e125cSJiandong Zheng {
591799e125cSJiandong Zheng 	uint32_t tmp = 0;
592799e125cSJiandong Zheng 
593799e125cSJiandong Zheng 	while (timeout > 10) {
594799e125cSJiandong Zheng 		tmp = readl(GMAC_MII_CTRL_ADDR);
595799e125cSJiandong Zheng 		if (tmp & (1 << GMAC_MII_BUSY_SHIFT)) {
596799e125cSJiandong Zheng 			udelay(10);
597799e125cSJiandong Zheng 			timeout -= 10;
598799e125cSJiandong Zheng 		} else {
599799e125cSJiandong Zheng 			break;
600799e125cSJiandong Zheng 		}
601799e125cSJiandong Zheng 	}
602799e125cSJiandong Zheng 	return tmp & (1 << GMAC_MII_BUSY_SHIFT);
603799e125cSJiandong Zheng }
604799e125cSJiandong Zheng 
gmac_miiphy_read(struct mii_dev * bus,int phyaddr,int devad,int reg)605dfcc496eSJoe Hershberger int gmac_miiphy_read(struct mii_dev *bus, int phyaddr, int devad, int reg)
606799e125cSJiandong Zheng {
607799e125cSJiandong Zheng 	uint32_t tmp = 0;
608dfcc496eSJoe Hershberger 	u16 value = 0;
609799e125cSJiandong Zheng 
610799e125cSJiandong Zheng 	/* Busy wait timeout is 1ms */
611799e125cSJiandong Zheng 	if (gmac_mii_busywait(1000)) {
6129b643e31SMasahiro Yamada 		pr_err("%s: Prepare MII read: MII/MDIO busy\n", __func__);
613799e125cSJiandong Zheng 		return -1;
614799e125cSJiandong Zheng 	}
615799e125cSJiandong Zheng 
616799e125cSJiandong Zheng 	/* Read operation */
617799e125cSJiandong Zheng 	tmp = GMAC_MII_DATA_READ_CMD;
618799e125cSJiandong Zheng 	tmp |= (phyaddr << GMAC_MII_PHY_ADDR_SHIFT) |
619799e125cSJiandong Zheng 		(reg << GMAC_MII_PHY_REG_SHIFT);
620799e125cSJiandong Zheng 	debug("MII read cmd 0x%x, phy 0x%x, reg 0x%x\n", tmp, phyaddr, reg);
621799e125cSJiandong Zheng 	writel(tmp, GMAC_MII_DATA_ADDR);
622799e125cSJiandong Zheng 
623799e125cSJiandong Zheng 	if (gmac_mii_busywait(1000)) {
6249b643e31SMasahiro Yamada 		pr_err("%s: MII read failure: MII/MDIO busy\n", __func__);
625799e125cSJiandong Zheng 		return -1;
626799e125cSJiandong Zheng 	}
627799e125cSJiandong Zheng 
628dfcc496eSJoe Hershberger 	value = readl(GMAC_MII_DATA_ADDR) & 0xffff;
629dfcc496eSJoe Hershberger 	debug("MII read data 0x%x\n", value);
630dfcc496eSJoe Hershberger 	return value;
631799e125cSJiandong Zheng }
632799e125cSJiandong Zheng 
gmac_miiphy_write(struct mii_dev * bus,int phyaddr,int devad,int reg,u16 value)633dfcc496eSJoe Hershberger int gmac_miiphy_write(struct mii_dev *bus, int phyaddr, int devad, int reg,
634dfcc496eSJoe Hershberger 		      u16 value)
635799e125cSJiandong Zheng {
636799e125cSJiandong Zheng 	uint32_t tmp = 0;
637799e125cSJiandong Zheng 
638799e125cSJiandong Zheng 	/* Busy wait timeout is 1ms */
639799e125cSJiandong Zheng 	if (gmac_mii_busywait(1000)) {
6409b643e31SMasahiro Yamada 		pr_err("%s: Prepare MII write: MII/MDIO busy\n", __func__);
641799e125cSJiandong Zheng 		return -1;
642799e125cSJiandong Zheng 	}
643799e125cSJiandong Zheng 
644799e125cSJiandong Zheng 	/* Write operation */
645799e125cSJiandong Zheng 	tmp = GMAC_MII_DATA_WRITE_CMD | (value & 0xffff);
646799e125cSJiandong Zheng 	tmp |= ((phyaddr << GMAC_MII_PHY_ADDR_SHIFT) |
647799e125cSJiandong Zheng 		(reg << GMAC_MII_PHY_REG_SHIFT));
648799e125cSJiandong Zheng 	debug("MII write cmd 0x%x, phy 0x%x, reg 0x%x, data 0x%x\n",
649799e125cSJiandong Zheng 	      tmp, phyaddr, reg, value);
650799e125cSJiandong Zheng 	writel(tmp, GMAC_MII_DATA_ADDR);
651799e125cSJiandong Zheng 
652799e125cSJiandong Zheng 	if (gmac_mii_busywait(1000)) {
6539b643e31SMasahiro Yamada 		pr_err("%s: MII write failure: MII/MDIO busy\n", __func__);
654799e125cSJiandong Zheng 		return -1;
655799e125cSJiandong Zheng 	}
656799e125cSJiandong Zheng 
657799e125cSJiandong Zheng 	return 0;
658799e125cSJiandong Zheng }
659799e125cSJiandong Zheng 
gmac_init_reset(void)660799e125cSJiandong Zheng void gmac_init_reset(void)
661799e125cSJiandong Zheng {
662799e125cSJiandong Zheng 	debug("%s enter\n", __func__);
663799e125cSJiandong Zheng 
664799e125cSJiandong Zheng 	/* set command config reg CC_SR */
665799e125cSJiandong Zheng 	reg32_set_bits(UNIMAC0_CMD_CFG_ADDR, CC_SR);
666799e125cSJiandong Zheng 	udelay(GMAC_RESET_DELAY);
667799e125cSJiandong Zheng }
668799e125cSJiandong Zheng 
gmac_clear_reset(void)669799e125cSJiandong Zheng void gmac_clear_reset(void)
670799e125cSJiandong Zheng {
671799e125cSJiandong Zheng 	debug("%s enter\n", __func__);
672799e125cSJiandong Zheng 
673799e125cSJiandong Zheng 	/* clear command config reg CC_SR */
674799e125cSJiandong Zheng 	reg32_clear_bits(UNIMAC0_CMD_CFG_ADDR, CC_SR);
675799e125cSJiandong Zheng 	udelay(GMAC_RESET_DELAY);
676799e125cSJiandong Zheng }
677799e125cSJiandong Zheng 
gmac_enable_local(bool en)678799e125cSJiandong Zheng static void gmac_enable_local(bool en)
679799e125cSJiandong Zheng {
680799e125cSJiandong Zheng 	uint32_t cmdcfg;
681799e125cSJiandong Zheng 
682799e125cSJiandong Zheng 	debug("%s enter\n", __func__);
683799e125cSJiandong Zheng 
684799e125cSJiandong Zheng 	/* read command config reg */
685799e125cSJiandong Zheng 	cmdcfg = readl(UNIMAC0_CMD_CFG_ADDR);
686799e125cSJiandong Zheng 
687799e125cSJiandong Zheng 	/* put mac in reset */
688799e125cSJiandong Zheng 	gmac_init_reset();
689799e125cSJiandong Zheng 
690799e125cSJiandong Zheng 	cmdcfg |= CC_SR;
691799e125cSJiandong Zheng 
692799e125cSJiandong Zheng 	/* first deassert rx_ena and tx_ena while in reset */
693799e125cSJiandong Zheng 	cmdcfg &= ~(CC_RE | CC_TE);
694799e125cSJiandong Zheng 	/* write command config reg */
695799e125cSJiandong Zheng 	writel(cmdcfg, UNIMAC0_CMD_CFG_ADDR);
696799e125cSJiandong Zheng 
697799e125cSJiandong Zheng 	/* bring mac out of reset */
698799e125cSJiandong Zheng 	gmac_clear_reset();
699799e125cSJiandong Zheng 
700799e125cSJiandong Zheng 	/* if not enable exit now */
701799e125cSJiandong Zheng 	if (!en)
702799e125cSJiandong Zheng 		return;
703799e125cSJiandong Zheng 
704799e125cSJiandong Zheng 	/* enable the mac transmit and receive paths now */
705799e125cSJiandong Zheng 	udelay(2);
706799e125cSJiandong Zheng 	cmdcfg &= ~CC_SR;
707799e125cSJiandong Zheng 	cmdcfg |= (CC_RE | CC_TE);
708799e125cSJiandong Zheng 
709799e125cSJiandong Zheng 	/* assert rx_ena and tx_ena when out of reset to enable the mac */
710799e125cSJiandong Zheng 	writel(cmdcfg, UNIMAC0_CMD_CFG_ADDR);
711799e125cSJiandong Zheng 
712799e125cSJiandong Zheng 	return;
713799e125cSJiandong Zheng }
714799e125cSJiandong Zheng 
gmac_enable(void)715799e125cSJiandong Zheng int gmac_enable(void)
716799e125cSJiandong Zheng {
717799e125cSJiandong Zheng 	gmac_enable_local(1);
718799e125cSJiandong Zheng 
719799e125cSJiandong Zheng 	/* clear interrupts */
720799e125cSJiandong Zheng 	writel(I_INTMASK, GMAC0_INT_STATUS_ADDR);
721799e125cSJiandong Zheng 	return 0;
722799e125cSJiandong Zheng }
723799e125cSJiandong Zheng 
gmac_disable(void)724799e125cSJiandong Zheng int gmac_disable(void)
725799e125cSJiandong Zheng {
726799e125cSJiandong Zheng 	gmac_enable_local(0);
727799e125cSJiandong Zheng 	return 0;
728799e125cSJiandong Zheng }
729799e125cSJiandong Zheng 
gmac_set_speed(int speed,int duplex)730799e125cSJiandong Zheng int gmac_set_speed(int speed, int duplex)
731799e125cSJiandong Zheng {
732799e125cSJiandong Zheng 	uint32_t cmdcfg;
733799e125cSJiandong Zheng 	uint32_t hd_ena;
734799e125cSJiandong Zheng 	uint32_t speed_cfg;
735799e125cSJiandong Zheng 
736799e125cSJiandong Zheng 	hd_ena = duplex ? 0 : CC_HD;
737799e125cSJiandong Zheng 	if (speed == 1000) {
738799e125cSJiandong Zheng 		speed_cfg = 2;
739799e125cSJiandong Zheng 	} else if (speed == 100) {
740799e125cSJiandong Zheng 		speed_cfg = 1;
741799e125cSJiandong Zheng 	} else if (speed == 10) {
742799e125cSJiandong Zheng 		speed_cfg = 0;
743799e125cSJiandong Zheng 	} else {
7449b643e31SMasahiro Yamada 		pr_err("%s: Invalid GMAC speed(%d)!\n", __func__, speed);
745799e125cSJiandong Zheng 		return -1;
746799e125cSJiandong Zheng 	}
747799e125cSJiandong Zheng 
748799e125cSJiandong Zheng 	cmdcfg = readl(UNIMAC0_CMD_CFG_ADDR);
749799e125cSJiandong Zheng 	cmdcfg &= ~(CC_ES_MASK | CC_HD);
750799e125cSJiandong Zheng 	cmdcfg |= ((speed_cfg << CC_ES_SHIFT) | hd_ena);
751799e125cSJiandong Zheng 
752799e125cSJiandong Zheng 	printf("Change GMAC speed to %dMB\n", speed);
753799e125cSJiandong Zheng 	debug("GMAC speed cfg 0x%x\n", cmdcfg);
754799e125cSJiandong Zheng 	writel(cmdcfg, UNIMAC0_CMD_CFG_ADDR);
755799e125cSJiandong Zheng 
756799e125cSJiandong Zheng 	return 0;
757799e125cSJiandong Zheng }
758799e125cSJiandong Zheng 
gmac_set_mac_addr(unsigned char * mac)759799e125cSJiandong Zheng int gmac_set_mac_addr(unsigned char *mac)
760799e125cSJiandong Zheng {
761799e125cSJiandong Zheng 	/* set our local address */
762799e125cSJiandong Zheng 	debug("GMAC: %02x:%02x:%02x:%02x:%02x:%02x\n",
763799e125cSJiandong Zheng 	      mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
764799e125cSJiandong Zheng 	writel(htonl(*(uint32_t *)mac), UNIMAC0_MAC_MSB_ADDR);
765799e125cSJiandong Zheng 	writew(htons(*(uint32_t *)&mac[4]), UNIMAC0_MAC_LSB_ADDR);
766799e125cSJiandong Zheng 
767799e125cSJiandong Zheng 	return 0;
768799e125cSJiandong Zheng }
769799e125cSJiandong Zheng 
gmac_mac_init(struct eth_device * dev)770799e125cSJiandong Zheng int gmac_mac_init(struct eth_device *dev)
771799e125cSJiandong Zheng {
772799e125cSJiandong Zheng 	struct eth_info *eth = (struct eth_info *)(dev->priv);
773799e125cSJiandong Zheng 	struct eth_dma *dma = &(eth->dma);
774799e125cSJiandong Zheng 
775799e125cSJiandong Zheng 	uint32_t tmp;
776799e125cSJiandong Zheng 	uint32_t cmdcfg;
777799e125cSJiandong Zheng 	int chipid;
778799e125cSJiandong Zheng 
779799e125cSJiandong Zheng 	debug("%s enter\n", __func__);
780799e125cSJiandong Zheng 
781799e125cSJiandong Zheng 	/* Always use GMAC0 */
782799e125cSJiandong Zheng 	printf("Using GMAC%d\n", 0);
783799e125cSJiandong Zheng 
784799e125cSJiandong Zheng 	/* Reset AMAC0 core */
785799e125cSJiandong Zheng 	writel(0, AMAC0_IDM_RESET_ADDR);
786799e125cSJiandong Zheng 	tmp = readl(AMAC0_IO_CTRL_DIRECT_ADDR);
787799e125cSJiandong Zheng 	/* Set clock */
788799e125cSJiandong Zheng 	tmp &= ~(1 << AMAC0_IO_CTRL_CLK_250_SEL_SHIFT);
789799e125cSJiandong Zheng 	tmp |= (1 << AMAC0_IO_CTRL_GMII_MODE_SHIFT);
790799e125cSJiandong Zheng 	/* Set Tx clock */
791799e125cSJiandong Zheng 	tmp &= ~(1 << AMAC0_IO_CTRL_DEST_SYNC_MODE_EN_SHIFT);
792799e125cSJiandong Zheng 	writel(tmp, AMAC0_IO_CTRL_DIRECT_ADDR);
793799e125cSJiandong Zheng 
794799e125cSJiandong Zheng 	/* reset gmac */
795799e125cSJiandong Zheng 	/*
796799e125cSJiandong Zheng 	 * As AMAC is just reset, NO need?
797799e125cSJiandong Zheng 	 * set eth_data into loopback mode to ensure no rx traffic
798799e125cSJiandong Zheng 	 * gmac_loopback(eth_data, TRUE);
799799e125cSJiandong Zheng 	 * ET_TRACE(("%s gmac loopback\n", __func__));
800799e125cSJiandong Zheng 	 * udelay(1);
801799e125cSJiandong Zheng 	 */
802799e125cSJiandong Zheng 
803799e125cSJiandong Zheng 	cmdcfg = readl(UNIMAC0_CMD_CFG_ADDR);
804799e125cSJiandong Zheng 	cmdcfg &= ~(CC_TE | CC_RE | CC_RPI | CC_TAI | CC_HD | CC_ML |
805799e125cSJiandong Zheng 		    CC_CFE | CC_RL | CC_RED | CC_PE | CC_TPI |
806799e125cSJiandong Zheng 		    CC_PAD_EN | CC_PF);
807799e125cSJiandong Zheng 	cmdcfg |= (CC_PROM | CC_NLC | CC_CFE);
808799e125cSJiandong Zheng 	/* put mac in reset */
809799e125cSJiandong Zheng 	gmac_init_reset();
810799e125cSJiandong Zheng 	writel(cmdcfg, UNIMAC0_CMD_CFG_ADDR);
811799e125cSJiandong Zheng 	gmac_clear_reset();
812799e125cSJiandong Zheng 
813799e125cSJiandong Zheng 	/* enable clear MIB on read */
814799e125cSJiandong Zheng 	reg32_set_bits(GMAC0_DEV_CTRL_ADDR, DC_MROR);
815799e125cSJiandong Zheng 	/* PHY: set smi_master to drive mdc_clk */
816799e125cSJiandong Zheng 	reg32_set_bits(GMAC0_PHY_CTRL_ADDR, PC_MTE);
817799e125cSJiandong Zheng 
818799e125cSJiandong Zheng 	/* clear persistent sw intstatus */
819799e125cSJiandong Zheng 	writel(0, GMAC0_INT_STATUS_ADDR);
820799e125cSJiandong Zheng 
821799e125cSJiandong Zheng 	if (dma_init(dma) < 0) {
8229b643e31SMasahiro Yamada 		pr_err("%s: GMAC dma_init failed\n", __func__);
823799e125cSJiandong Zheng 		goto err_exit;
824799e125cSJiandong Zheng 	}
825799e125cSJiandong Zheng 
826799e125cSJiandong Zheng 	chipid = CHIPID;
827799e125cSJiandong Zheng 	printf("%s: Chip ID: 0x%x\n", __func__, chipid);
828799e125cSJiandong Zheng 
829799e125cSJiandong Zheng 	/* set switch bypass mode */
830799e125cSJiandong Zheng 	tmp = readl(SWITCH_GLOBAL_CONFIG_ADDR);
831799e125cSJiandong Zheng 	tmp |= (1 << CDRU_SWITCH_BYPASS_SWITCH_SHIFT);
832799e125cSJiandong Zheng 
833799e125cSJiandong Zheng 	/* Switch mode */
834799e125cSJiandong Zheng 	/* tmp &= ~(1 << CDRU_SWITCH_BYPASS_SWITCH_SHIFT); */
835799e125cSJiandong Zheng 
836799e125cSJiandong Zheng 	writel(tmp, SWITCH_GLOBAL_CONFIG_ADDR);
837799e125cSJiandong Zheng 
838799e125cSJiandong Zheng 	tmp = readl(CRMU_CHIP_IO_PAD_CONTROL_ADDR);
839799e125cSJiandong Zheng 	tmp &= ~(1 << CDRU_IOMUX_FORCE_PAD_IN_SHIFT);
840799e125cSJiandong Zheng 	writel(tmp, CRMU_CHIP_IO_PAD_CONTROL_ADDR);
841799e125cSJiandong Zheng 
842799e125cSJiandong Zheng 	/* Set MDIO to internal GPHY */
843799e125cSJiandong Zheng 	tmp = readl(GMAC_MII_CTRL_ADDR);
844799e125cSJiandong Zheng 	/* Select internal MDC/MDIO bus*/
845799e125cSJiandong Zheng 	tmp &= ~(1 << GMAC_MII_CTRL_BYP_SHIFT);
846799e125cSJiandong Zheng 	/* select MDC/MDIO connecting to on-chip internal PHYs */
847799e125cSJiandong Zheng 	tmp &= ~(1 << GMAC_MII_CTRL_EXT_SHIFT);
848799e125cSJiandong Zheng 	/*
849799e125cSJiandong Zheng 	 * give bit[6:0](MDCDIV) with required divisor to set
850799e125cSJiandong Zheng 	 * the MDC clock frequency, 66MHZ/0x1A=2.5MHZ
851799e125cSJiandong Zheng 	 */
852799e125cSJiandong Zheng 	tmp |= 0x1A;
853799e125cSJiandong Zheng 
854799e125cSJiandong Zheng 	writel(tmp, GMAC_MII_CTRL_ADDR);
855799e125cSJiandong Zheng 
856799e125cSJiandong Zheng 	if (gmac_mii_busywait(1000)) {
8579b643e31SMasahiro Yamada 		pr_err("%s: Configure MDIO: MII/MDIO busy\n", __func__);
858799e125cSJiandong Zheng 		goto err_exit;
859799e125cSJiandong Zheng 	}
860799e125cSJiandong Zheng 
861799e125cSJiandong Zheng 	/* Configure GMAC0 */
862799e125cSJiandong Zheng 	/* enable one rx interrupt per received frame */
863799e125cSJiandong Zheng 	writel(1 << GMAC0_IRL_FRAMECOUNT_SHIFT, GMAC0_INTR_RECV_LAZY_ADDR);
864799e125cSJiandong Zheng 
865799e125cSJiandong Zheng 	/* read command config reg */
866799e125cSJiandong Zheng 	cmdcfg = readl(UNIMAC0_CMD_CFG_ADDR);
867799e125cSJiandong Zheng 	/* enable 802.3x tx flow control (honor received PAUSE frames) */
868799e125cSJiandong Zheng 	cmdcfg &= ~CC_RPI;
869799e125cSJiandong Zheng 	/* enable promiscuous mode */
870799e125cSJiandong Zheng 	cmdcfg |= CC_PROM;
871799e125cSJiandong Zheng 	/* Disable loopback mode */
872799e125cSJiandong Zheng 	cmdcfg &= ~CC_ML;
873799e125cSJiandong Zheng 	/* set the speed */
874799e125cSJiandong Zheng 	cmdcfg &= ~(CC_ES_MASK | CC_HD);
875799e125cSJiandong Zheng 	/* Set to 1Gbps and full duplex by default */
876799e125cSJiandong Zheng 	cmdcfg |= (2 << CC_ES_SHIFT);
877799e125cSJiandong Zheng 
878799e125cSJiandong Zheng 	/* put mac in reset */
879799e125cSJiandong Zheng 	gmac_init_reset();
880799e125cSJiandong Zheng 	/* write register */
881799e125cSJiandong Zheng 	writel(cmdcfg, UNIMAC0_CMD_CFG_ADDR);
882799e125cSJiandong Zheng 	/* bring mac out of reset */
883799e125cSJiandong Zheng 	gmac_clear_reset();
884799e125cSJiandong Zheng 
885799e125cSJiandong Zheng 	/* set max frame lengths; account for possible vlan tag */
886799e125cSJiandong Zheng 	writel(PKTSIZE + 32, UNIMAC0_FRM_LENGTH_ADDR);
887799e125cSJiandong Zheng 
888799e125cSJiandong Zheng 	return 0;
889799e125cSJiandong Zheng 
890799e125cSJiandong Zheng err_exit:
891799e125cSJiandong Zheng 	dma_deinit(dma);
892799e125cSJiandong Zheng 	return -1;
893799e125cSJiandong Zheng }
894799e125cSJiandong Zheng 
gmac_add(struct eth_device * dev)895799e125cSJiandong Zheng int gmac_add(struct eth_device *dev)
896799e125cSJiandong Zheng {
897799e125cSJiandong Zheng 	struct eth_info *eth = (struct eth_info *)(dev->priv);
898799e125cSJiandong Zheng 	struct eth_dma *dma = &(eth->dma);
899799e125cSJiandong Zheng 	void *tmp;
900799e125cSJiandong Zheng 
901799e125cSJiandong Zheng 	/*
9025c624b9eSSuji Velupillai 	 * Desc has to be 16-byte aligned. But for dcache flush it must be
9035c624b9eSSuji Velupillai 	 * aligned to ARCH_DMA_MINALIGN.
904799e125cSJiandong Zheng 	 */
9055c624b9eSSuji Velupillai 	tmp = memalign(ARCH_DMA_MINALIGN, DESCP_SIZE_ALIGNED * TX_BUF_NUM);
906799e125cSJiandong Zheng 	if (tmp == NULL) {
907799e125cSJiandong Zheng 		printf("%s: Failed to allocate TX desc Buffer\n", __func__);
908799e125cSJiandong Zheng 		return -1;
909799e125cSJiandong Zheng 	}
910799e125cSJiandong Zheng 
9115c624b9eSSuji Velupillai 	dma->tx_desc_aligned = (void *)tmp;
912799e125cSJiandong Zheng 	debug("TX Descriptor Buffer: %p; length: 0x%x\n",
9135c624b9eSSuji Velupillai 	      dma->tx_desc_aligned, DESCP_SIZE_ALIGNED * TX_BUF_NUM);
914799e125cSJiandong Zheng 
9155c624b9eSSuji Velupillai 	tmp = memalign(ARCH_DMA_MINALIGN, TX_BUF_SIZE_ALIGNED * TX_BUF_NUM);
916799e125cSJiandong Zheng 	if (tmp == NULL) {
917799e125cSJiandong Zheng 		printf("%s: Failed to allocate TX Data Buffer\n", __func__);
9185c624b9eSSuji Velupillai 		free(dma->tx_desc_aligned);
919799e125cSJiandong Zheng 		return -1;
920799e125cSJiandong Zheng 	}
921799e125cSJiandong Zheng 	dma->tx_buf = (uint8_t *)tmp;
922799e125cSJiandong Zheng 	debug("TX Data Buffer: %p; length: 0x%x\n",
9235c624b9eSSuji Velupillai 	      dma->tx_buf, TX_BUF_SIZE_ALIGNED * TX_BUF_NUM);
924799e125cSJiandong Zheng 
9255c624b9eSSuji Velupillai 	/* Desc has to be 16-byte aligned */
9265c624b9eSSuji Velupillai 	tmp = memalign(ARCH_DMA_MINALIGN, DESCP_SIZE_ALIGNED * RX_BUF_NUM);
927799e125cSJiandong Zheng 	if (tmp == NULL) {
928799e125cSJiandong Zheng 		printf("%s: Failed to allocate RX Descriptor\n", __func__);
9295c624b9eSSuji Velupillai 		free(dma->tx_desc_aligned);
930799e125cSJiandong Zheng 		free(dma->tx_buf);
931799e125cSJiandong Zheng 		return -1;
932799e125cSJiandong Zheng 	}
9335c624b9eSSuji Velupillai 	dma->rx_desc_aligned = (void *)tmp;
934799e125cSJiandong Zheng 	debug("RX Descriptor Buffer: %p, length: 0x%x\n",
9355c624b9eSSuji Velupillai 	      dma->rx_desc_aligned, DESCP_SIZE_ALIGNED * RX_BUF_NUM);
936799e125cSJiandong Zheng 
9375c624b9eSSuji Velupillai 	tmp = memalign(ARCH_DMA_MINALIGN, RX_BUF_SIZE_ALIGNED * RX_BUF_NUM);
938799e125cSJiandong Zheng 	if (tmp == NULL) {
939799e125cSJiandong Zheng 		printf("%s: Failed to allocate RX Data Buffer\n", __func__);
9405c624b9eSSuji Velupillai 		free(dma->tx_desc_aligned);
941799e125cSJiandong Zheng 		free(dma->tx_buf);
9425c624b9eSSuji Velupillai 		free(dma->rx_desc_aligned);
943799e125cSJiandong Zheng 		return -1;
944799e125cSJiandong Zheng 	}
9455c624b9eSSuji Velupillai 	dma->rx_buf = (uint8_t *)tmp;
946799e125cSJiandong Zheng 	debug("RX Data Buffer: %p; length: 0x%x\n",
9475c624b9eSSuji Velupillai 	      dma->rx_buf, RX_BUF_SIZE_ALIGNED * RX_BUF_NUM);
948799e125cSJiandong Zheng 
949799e125cSJiandong Zheng 	g_dmactrlflags = 0;
950799e125cSJiandong Zheng 
951799e125cSJiandong Zheng 	eth->phy_interface = PHY_INTERFACE_MODE_GMII;
952799e125cSJiandong Zheng 
953799e125cSJiandong Zheng 	dma->tx_packet = gmac_tx_packet;
954799e125cSJiandong Zheng 	dma->check_tx_done = gmac_check_tx_done;
955799e125cSJiandong Zheng 
956799e125cSJiandong Zheng 	dma->check_rx_done = gmac_check_rx_done;
957799e125cSJiandong Zheng 
958799e125cSJiandong Zheng 	dma->enable_dma = gmac_enable_dma;
959799e125cSJiandong Zheng 	dma->disable_dma = gmac_disable_dma;
960799e125cSJiandong Zheng 
961799e125cSJiandong Zheng 	eth->miiphy_read = gmac_miiphy_read;
962799e125cSJiandong Zheng 	eth->miiphy_write = gmac_miiphy_write;
963799e125cSJiandong Zheng 
964799e125cSJiandong Zheng 	eth->mac_init = gmac_mac_init;
965799e125cSJiandong Zheng 	eth->disable_mac = gmac_disable;
966799e125cSJiandong Zheng 	eth->enable_mac = gmac_enable;
967799e125cSJiandong Zheng 	eth->set_mac_addr = gmac_set_mac_addr;
968799e125cSJiandong Zheng 	eth->set_mac_speed = gmac_set_speed;
969799e125cSJiandong Zheng 
970799e125cSJiandong Zheng 	return 0;
971799e125cSJiandong Zheng }
972