1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
|
From b17d75d2c1dc6cd1d55bcddbf7d3d4242e85e88e Mon Sep 17 00:00:00 2001
From: Anji J <anji.jagarlmudi@freescale.com>
Date: Fri, 20 May 2016 15:25:12 +0530
Subject: [PATCH 43/93] DNCPE-296 PFE reset workaround
LS1012A PFE doesn't have global reset control.
Due to this Linux pfe doesn't work when it was started at U-boot
This patch provides U-boot command to stop pfe, that should be used before starting Linux.
Signed-off-by: Anjaneyulu Jagarlmudi <anji.jagarlmudi@nxp.com>>
Signed-off-by: Prabhakar Kushwaha <prabhakar.kushwaha@nxp.com>
---
common/cmd_pfe_commands.c | 83 +++++++++++++++++++++++++++++++++++-
drivers/net/pfe_eth/pfe/cbus/hif.h | 3 ++
drivers/net/pfe_eth/pfe/pfe.h | 2 +
drivers/net/pfe_eth/pfe_driver.c | 58 ++++++++++++++++++++-----
drivers/net/pfe_eth/pfe_eth.c | 6 +--
5 files changed, 136 insertions(+), 16 deletions(-)
diff --git a/common/cmd_pfe_commands.c b/common/cmd_pfe_commands.c
index f9f92c7..0e22097 100644
--- a/common/cmd_pfe_commands.c
+++ b/common/cmd_pfe_commands.c
@@ -35,6 +35,7 @@
#include "../drivers/net/pfe_eth/pfe/cbus/gpi.h"
DECLARE_GLOBAL_DATA_PTR;
+void hif_rx_desc_disable(void);
int pfe_load_elf(int pe_mask, const struct firmware *fw);
int ls1012a_gemac_initialize(bd_t * bis, int dev_id, char *devname);
@@ -593,7 +594,9 @@ void bmu(int id, void *base)
}
#define PESTATUS_ADDR_CLASS 0x800
+#define PEMBOX_ADDR_CLASS 0x890
#define PESTATUS_ADDR_TMU 0x80
+#define PEMBOX_ADDR_TMU 0x290
#define PESTATUS_ADDR_UTIL 0x0
static void pfe_pe_status(int argc, char * const argv[])
@@ -857,7 +860,6 @@ void hif_rx_enable(void)
void hif_rx_disable(void)
}
#endif
-
#define ROUTE_TABLE_START (CONFIG_DDR_PHYS_BASEADDR+ROUTE_TABLE_BASEADDR)
static void pfe_command_fftest(int argc, char * const argv[])
{
@@ -865,7 +867,6 @@ static void pfe_command_fftest(int argc, char * const argv[])
struct eth_device *edev_eth0;
struct eth_device *edev_eth1;
-
// open eth0 and eth1
edev_eth0 = eth_get_dev_by_name("pfe_eth0");
if (!edev_eth0)
@@ -916,6 +917,80 @@ static void pfe_command_start(int argc, char * const argv[])
}
#endif
+#ifdef PFE_LS1012A_RESET_WA
+/*This function sends a dummy packet to HIF through TMU3 */
+static void send_dummy_pkt_to_hif(void)
+{
+ u32 buf;
+ static u32 dummy_pkt[] = {
+ 0x4200800a, 0x01000003, 0x00018100, 0x00000000,
+ 0x33221100, 0x2b785544, 0xd73093cb, 0x01000608,
+ 0x04060008, 0x2b780200, 0xd73093cb, 0x0a01a8c0,
+ 0x33221100, 0xa8c05544, 0x00000301, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0xbe86c51f };
+
+ /*Allocate BMU2 buffer */
+ buf = readl(BMU2_BASE_ADDR + BMU_ALLOC_CTRL);
+
+ printf("Sending a dummy pkt to HIF %x\n", buf);
+ buf += 0x80;
+ memcpy((void *)DDR_PFE_TO_VIRT(buf), dummy_pkt, sizeof(dummy_pkt));
+ /*Write length and pkt to TMU*/
+ writel(0x03000042, TMU_PHY_INQ_PKTPTR);
+ writel(buf, TMU_PHY_INQ_PKTINFO);
+
+}
+
+static void pfe_command_stop(int argc, char * const argv[])
+{
+ int id;
+ u32 rx_status;
+ printf("Stopping PFE \n");
+
+ /*Mark all descriptors as LAST_BD */
+ hif_rx_desc_disable();
+
+ /*If HIF Rx BDP is busy send a dummy packet */
+ rx_status = readl(HIF_RX_STATUS);
+ printf("rx_status %x %x\n",rx_status, BDP_CSR_RX_DMA_ACTV);
+ if(rx_status & BDP_CSR_RX_DMA_ACTV)
+ send_dummy_pkt_to_hif();
+ udelay(10);
+
+ if(readl(HIF_RX_STATUS) & BDP_CSR_RX_DMA_ACTV)
+ printf("Unable to stop HIF\n");
+
+ /*Disable Class PEs */
+
+ for (id = CLASS0_ID; id <= CLASS_MAX_ID; id++)
+ {
+ printf("Stop %d\n", id);
+ /*Inform PE to stop */
+ pe_dmem_write(id, cpu_to_be32(1), PEMBOX_ADDR_CLASS, 4);
+ udelay(10);
+
+ printf("Reading %d\n", id);
+ /*Read status */
+ if(!pe_dmem_read(id, PEMBOX_ADDR_CLASS+4, 4))
+ printf("Failed to stop PE%d\n", id);
+ }
+ /*Disable TMU PEs */
+ for (id = TMU0_ID; id <= TMU_MAX_ID; id++)
+ {
+ if(id == TMU2_ID) continue;
+
+ printf("Stop %d\n", id);
+ /*Inform PE to stop */
+ pe_dmem_write(id, 1, PEMBOX_ADDR_TMU, 4);
+ udelay(10);
+
+ printf("Reading %d\n", id);
+ /*Read status */
+ if(!pe_dmem_read(id, PEMBOX_ADDR_TMU+4, 4))
+ printf("Failed to stop PE%d\n", id);
+ }
+}
+#endif
static int pfe_command(cmd_tbl_t *cmdtp, int flag, int argc,
char * const argv[])
@@ -965,6 +1040,10 @@ static int pfe_command(cmd_tbl_t *cmdtp, int flag, int argc,
else if (strcmp(argv[1], "start") == 0)
pfe_command_start(argc, argv);
#endif
+#ifdef PFE_LS1012A_RESET_WA
+ else if (strcmp(argv[1], "stop") == 0)
+ pfe_command_stop(argc, argv);
+#endif
else
{
printf("Unknown option: %s\n", argv[1]);
diff --git a/drivers/net/pfe_eth/pfe/cbus/hif.h b/drivers/net/pfe_eth/pfe/cbus/hif.h
index a4dd7c2..2329faa 100644
--- a/drivers/net/pfe_eth/pfe/cbus/hif.h
+++ b/drivers/net/pfe_eth/pfe/cbus/hif.h
@@ -34,6 +34,9 @@
#define HIF_CTRL_BDP_POLL_CTRL_EN (1<<1)
#define HIF_CTRL_BDP_CH_START_WSTB (1<<2)
+/*HIF_RX_STATUS bits */
+#define BDP_CSR_RX_DMA_ACTV (1<<16)
+
/*HIF_INT_ENABLE bits */
#define HIF_INT_EN (1 << 0)
#define HIF_RXBD_INT_EN (1 << 1)
diff --git a/drivers/net/pfe_eth/pfe/pfe.h b/drivers/net/pfe_eth/pfe/pfe.h
index e8e2221..6994a20 100644
--- a/drivers/net/pfe_eth/pfe/pfe.h
+++ b/drivers/net/pfe_eth/pfe/pfe.h
@@ -1,6 +1,8 @@
#ifndef _PFE_H_
#define _PFE_H_
+#define PFE_LS1012A_RESET_WA
+
#define CLASS_DMEM_BASE_ADDR(i) (0x00000000 | ((i) << 20))
#define CLASS_IMEM_BASE_ADDR(i) (0x00000000 | ((i) << 20)) /* Only valid for mem access register interface */
#define CLASS_DMEM_SIZE 0x00002000
diff --git a/drivers/net/pfe_eth/pfe_driver.c b/drivers/net/pfe_eth/pfe_driver.c
index ca00e98..b06a352 100644
--- a/drivers/net/pfe_eth/pfe_driver.c
+++ b/drivers/net/pfe_eth/pfe_driver.c
@@ -51,13 +51,18 @@ int pfe_recv(unsigned int *pkt_ptr, int *phy_port)
struct rx_desc_s *rx_desc = g_rx_desc;
struct bufDesc *bd;
int len = -1;
- //volatile u32 ctrl;
+ volatile u32 ctrl;
struct hif_header_s *hif_header;
bd = rx_desc->rxBase + rx_desc->rxToRead;
- if (bd->ctrl & BD_CTRL_DESC_EN)
+ if (bd->ctrl & BD_CTRL_DESC_EN) {
+ if(!(readl(HIF_RX_STATUS) & BDP_CSR_RX_DMA_ACTV)){
+ /*If BDP is not active give write strobe */
+ writel((readl(HIF_RX_CTRL) | HIF_CTRL_BDP_CH_START_WSTB), HIF_RX_CTRL);
+ }
return len; //No pending Rx packet
+ }
/* this len include hif_header(8bytes) */
len = bd->ctrl & 0xFFFF;
@@ -69,7 +74,7 @@ int pfe_recv(unsigned int *pkt_ptr, int *phy_port)
dprint("Pkt recv'd: Pkt ptr(%p), len(%d), gemac_port(%d) status(%08x)\n",
hif_header, len, hif_header->port_no, bd->status);
-#if 0
+#if DEBUG
{
int i;
unsigned char *p = (unsigned char *)hif_header;
@@ -85,20 +90,26 @@ int pfe_recv(unsigned int *pkt_ptr, int *phy_port)
*pkt_ptr = (unsigned int )(hif_header + 1);
*phy_port = hif_header->port_no;
len -= sizeof(struct hif_header_s);
-#if 0
+
+#if defined(PFE_LS1012A_RESET_WA)
/* reset bd control field */
- ctrl = (MAX_FRAME_SIZE | BD_CTRL_DESC_EN | BD_CTRL_DIR);
+ ctrl = (MAX_FRAME_SIZE | BD_CTRL_LAST_BD | BD_CTRL_LIFM | BD_CTRL_DESC_EN | BD_CTRL_DIR);
+#else
+ /* reset bd control field */
+ ctrl = (MAX_FRAME_SIZE | BD_CTRL_LIFM | BD_CTRL_DESC_EN | BD_CTRL_DIR);
+ /* If we use BD_CTRL_LAST_BD, rxToRead never changes */
+ rx_desc->rxToRead = (rx_desc->rxToRead + 1) & (rx_desc->rxRingSize - 1);
+#endif
bd->ctrl = ctrl;
bd->status = 0;
- rx_desc->rxToRead = (rx_desc->rxToRead + 1) & (rx_desc->rxRingSize - 1);
/* Give START_STROBE to BDP to fetch the descriptor __NOW__,
* BDP need not to wait for rx_poll_cycle time to fetch the descriptor,
* In idle state (ie., no rx pkt), BDP will not fetch
* the descriptor even if strobe is given(I think) */
writel((readl(HIF_RX_CTRL) | HIF_CTRL_BDP_CH_START_WSTB), HIF_RX_CTRL);
-#endif
+
return len;
}
@@ -298,14 +309,37 @@ void hif_rx_desc_dump(void)
rx_desc = g_rx_desc;
bd_va = rx_desc->rxBase;
- printf("HIF rx desc: base_va: %p, base_pa: %08x\n", rx_desc->rxBase, rx_desc->rxBase_pa);
+ dprint("HIF rx desc: base_va: %p, base_pa: %08x\n", rx_desc->rxBase, rx_desc->rxBase_pa);
for (i=0; i < rx_desc->rxRingSize; i++) {
-// printf("status: %08x, ctrl: %08x, data: %08x, next: %p\n",
-// bd_va->status, bd_va->ctrl, bd_va->data, bd_va->next);
+ dprint("status: %08x, ctrl: %08x, data: %08x, next: %p\n",
+ bd_va->status, bd_va->ctrl, bd_va->data, bd_va->next);
+ bd_va++;
+ }
+}
+
+/** This function mark all Rx descriptors as LAST_BD.
+ */
+void hif_rx_desc_disable(void)
+{
+ int i;
+ struct rx_desc_s *rx_desc;
+ struct bufDesc *bd_va;
+
+ if (g_rx_desc == NULL) {
+ printf("%s: HIF Rx desc not initialized \n", __func__);
+ return;
+ }
+
+ rx_desc = g_rx_desc;
+ bd_va = rx_desc->rxBase;
+
+ for (i=0; i < rx_desc->rxRingSize; i++) {
+ bd_va->ctrl |= BD_CTRL_LAST_BD;
bd_va++;
}
}
+
/** HIF Rx Desc initialization function.
*/
static int hif_rx_desc_init(struct pfe *pfe)
@@ -348,7 +382,11 @@ static int hif_rx_desc_init(struct pfe *pfe)
memset(bd_va, 0, sizeof(struct bufDesc) * rx_desc->rxRingSize);
+#if defined(PFE_LS1012A_RESET_WA)
+ ctrl = (MAX_FRAME_SIZE | BD_CTRL_LAST_BD | BD_CTRL_DESC_EN | BD_CTRL_DIR | BD_CTRL_LIFM);
+#else
ctrl = (MAX_FRAME_SIZE | BD_CTRL_DESC_EN | BD_CTRL_DIR | BD_CTRL_LIFM);
+#endif
for (i=0; i < rx_desc->rxRingSize; i++) {
bd_va->next = (u32 )(bd_pa + 1);
bd_va->ctrl = ctrl;
diff --git a/drivers/net/pfe_eth/pfe_eth.c b/drivers/net/pfe_eth/pfe_eth.c
index 40ac095..40f2c39 100644
--- a/drivers/net/pfe_eth/pfe_eth.c
+++ b/drivers/net/pfe_eth/pfe_eth.c
@@ -48,7 +48,7 @@ static void ls1012a_gemac_enable(void *gemac_base)
writel(readl(gemac_base + EMAC_ECNTRL_REG) | EMAC_ECNTRL_ETHER_EN, gemac_base + EMAC_ECNTRL_REG);
}
-static void ls1012a_gemac_dsable(void *gemac_base)
+static void ls1012a_gemac_disable(void *gemac_base)
{
writel(readl(gemac_base + EMAC_ECNTRL_REG) & ~EMAC_ECNTRL_ETHER_EN, gemac_base + EMAC_ECNTRL_REG);
}
@@ -113,7 +113,7 @@ static void ls1012a_eth_halt(struct eth_device *edev)
{
struct ls1012a_eth_dev *priv = (struct ls1012a_eth_dev *)edev->priv;
- ls1012a_gemac_enable(priv->gem->gemac_base);
+ ls1012a_gemac_disable(priv->gem->gemac_base);
gpi_disable(priv->gem->egpi_base);
@@ -216,14 +216,12 @@ static int ls1012a_eth_recv(struct eth_device *dev)
dprint("Rx pkt: pkt_buf(%08x), phy_port(%d), len(%d)\n", pkt_buf, phy_port, len);
if (phy_port != priv->gemac_port) {
printf("Rx pkt not on expected port\n");
- pfe_recv_ack();
return 0;
}
// Pass the packet up to the protocol layers.
net_process_received_packet((uchar *)pkt_buf, len);
- pfe_recv_ack();
return 0;
}
--
1.7.9.5
|