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