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

