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