[qca-ssdk]: Add ess reset to ssdk

Add ess reset to ssdk.

Change-Id: I777ce470b10f0094e9abb1d640b8519768b049ac
Signed-off-by: xiaofeis <xiaofeis@codeaurora.org>
diff --git a/include/init/ssdk_plat.h b/include/init/ssdk_plat.h
index 825d032..a3c25b7 100755
--- a/include/init/ssdk_plat.h
+++ b/include/init/ssdk_plat.h
@@ -231,4 +231,12 @@
 qca_ar8327_phy_dbg_read(a_uint32_t dev_id, a_uint32_t phy_addr,
 		                          a_uint16_t dbg_addr, a_uint16_t *dbg_data);
 
+void 
+qca_phy_mmd_write(u32 dev_id, u32 phy_id,
+                     u16 mmd_num, u16 reg_id, u16 reg_val);
+
+u16 
+qca_phy_mmd_read(u32 dev_id, u32 phy_id,
+		u16 mmd_num, u16 reg_id);
+
 #endif
diff --git a/src/init/ssdk_init.c b/src/init/ssdk_init.c
index 211d097..551e836 100755
--- a/src/init/ssdk_init.c
+++ b/src/init/ssdk_init.c
@@ -84,6 +84,9 @@
 #ifdef IN_RFS
 struct rfs_device rfs_dev;
 struct notifier_block ssdk_inet_notifier;
+#if defined(CONFIG_RFS_ACCEL)
+struct notifier_block ssdk_dev_notifier;
+#endif
 #endif
 
 /*
@@ -1543,6 +1546,216 @@
 	return SW_FAIL;
 }
 
+#if defined(CONFIG_OF) && (LINUX_VERSION_CODE >= KERNEL_VERSION(3,14,0))
+struct reset_control *ess_rst;
+void ssdk_ess_reset()
+{
+	reset_control_assert(ess_rst);
+	mdelay(10);
+	reset_control_deassert(ess_rst);
+	mdelay(100);
+}
+#endif
+
+
+void ssdk_psgmii_self_test()
+{
+	int i = 0, phy = 0,j=0;
+	int reset = 0;
+	u32 value = 0;
+	u32 phy_t_status = 0;
+
+	qca_ar8327_phy_write(0, 4, 0x1f, 0x8500);/*switch to access MII reg for copper*/
+	for(phy = 0; phy < 5; phy++) {
+		/*enable phy mdio broadcast write*/
+		qca_phy_mmd_write(0, phy, 7, 0x8028, 0x801f);
+	}
+
+	/* force no link by power down */
+	qca_ar8327_phy_write(0, 0x1f, 0x0, 0x1840);
+
+	/*packet number*/
+	qca_phy_mmd_write(0, 0x1f, 7, 0x8021, 0x3000);
+	qca_phy_mmd_write(0, 0x1f, 7, 0x8062, 0x05e0);
+
+	/*fix mdi status */
+	qca_ar8327_phy_write(0, 0x1f, 0x10, 0x6800);
+
+	for(i = 0; i < 100; i++)
+	{
+		phy_t_status = 0;
+
+		for(phy = 0; phy < 5; phy++) {
+			value = readl(hw_addr+0x66c+phy*0xc);
+			writel((value|(1<<21)), (hw_addr+0x66c+phy*0xc));
+		}
+
+		for (phy = 0;phy < 5; phy++)
+		{
+			u32 tx_counter_ok, tx_counter_error;
+			u32 rx_counter_ok, rx_counter_error;
+			u32 tx_counter_ok_high16;
+			u32 rx_counter_ok_high16;
+			u32 tx_ok,rx_ok;
+			qca_ar8327_phy_write(0, phy, 0x0, 0x9000);
+			qca_ar8327_phy_write(0, phy, 0x0, 0x4140);
+			j=0;
+			while (j<100)
+			{
+				u16 status;
+				qca_ar8327_phy_read(0, phy, 0x11, &status);
+				if(status & (1 << 10))
+					break;
+				mdelay(10);
+				j++;
+			}
+
+			/*enable check*/
+			qca_phy_mmd_write(0, phy, 7, 0x8029, 0x0000);
+			qca_phy_mmd_write(0, phy, 7, 0x8029, 0x0003);
+
+			/*start traffic*/
+			qca_phy_mmd_write(0, phy, 7, 0x8020, 0xa000);
+			mdelay(200);
+
+			/*check counter*/
+			tx_counter_ok = qca_phy_mmd_read(0, phy, 7, 0x802e);
+			tx_counter_ok_high16 = qca_phy_mmd_read(0, phy, 7, 0x802d);
+			tx_counter_error = qca_phy_mmd_read(0, phy, 7, 0x802f);
+			rx_counter_ok = qca_phy_mmd_read(0, phy, 7, 0x802b);
+			rx_counter_ok_high16 = qca_phy_mmd_read(0, phy, 7, 0x802a);
+			rx_counter_error = qca_phy_mmd_read(0, phy, 7, 0x802c);
+			tx_ok = tx_counter_ok + (tx_counter_ok_high16<<16);
+			rx_ok = rx_counter_ok + (rx_counter_ok_high16<<16);  
+			if( tx_ok== 0x3000 && tx_counter_error == 0)/*success*/
+			{
+				phy_t_status &= (~(1<<phy));
+			}
+			else
+			{
+				printk("tx_ok = 0x%x, rx_ok = 0x%x, tx_counter_error = 0x%x, rx_counter_error = 0x%x\n",
+						tx_ok, rx_ok, tx_counter_error, rx_counter_error);
+				printk("PHY %d single test PSGMII issue happen \n", phy);           
+				phy_t_status |= (1<<phy);
+			}
+
+			qca_ar8327_phy_write(0, phy, 0x0, 0x1840);
+		}
+
+		qca_ar8327_phy_write(0, 0x1f, 0x0, 0x9000);
+
+		qca_ar8327_phy_write(0, 0x1f, 0x0, 0x4140);
+
+		j=0;
+		while(j < 100)
+		{
+			for(phy = 0; phy < 5; phy++)
+			{
+				u16 status;
+				qca_ar8327_phy_read(0, phy, 0x11, &status);
+				if(!(status & (1 << 10)))
+					break;
+			}
+
+			if(phy >= 5)
+				break;
+			mdelay(10);
+			j++;
+		}
+		/*enable check*/
+		qca_phy_mmd_write(0, 0x1f, 7, 0x8029, 0x0000);
+		qca_phy_mmd_write(0, 0x1f, 7, 0x8029, 0x0003);
+
+		/*start traffic*/
+		qca_phy_mmd_write(0, 0x1f, 7, 0x8020, 0xa000);
+		mdelay(200);
+		for(phy = 0; phy < 5; phy++)
+		{
+			u32 tx_counter_ok, tx_counter_error;
+			u32 rx_counter_ok, rx_counter_error;
+			u32 tx_counter_ok_high16;
+			u32 rx_counter_ok_high16;
+			u32 tx_ok,rx_ok;
+			/*check counter*/
+			tx_counter_ok = qca_phy_mmd_read(0, phy, 7, 0x802e);
+			tx_counter_ok_high16 = qca_phy_mmd_read(0, phy, 7, 0x802d);
+			tx_counter_error = qca_phy_mmd_read(0, phy, 7, 0x802f);
+			rx_counter_ok = qca_phy_mmd_read(0, phy, 7, 0x802b);
+			rx_counter_ok_high16 = qca_phy_mmd_read(0, phy, 7, 0x802a);
+			rx_counter_error = qca_phy_mmd_read(0, phy, 7, 0x802c);
+			tx_ok = tx_counter_ok + (tx_counter_ok_high16<<16);
+			rx_ok = rx_counter_ok + (rx_counter_ok_high16<<16);
+			if( tx_ok== 0x3000 && tx_counter_error == 0)/*success*/
+			{
+				phy_t_status &= (~(1<<(phy+8)));
+			}
+			else
+			{
+				printk("tx_ok = 0x%x, rx_ok = 0x%x, tx_counter_error = 0x%x, rx_counter_error = 0x%x\n",
+						tx_ok, rx_ok, tx_counter_error, rx_counter_error);
+				printk("PHY %d PSGMII issue happen,Reset PSGMII!!!!!!\n", phy);
+				phy_t_status |= (1<<(phy+8));
+			}
+		}
+		printk("PHY all test 0x%x \r\n",phy_t_status);
+		if (phy_t_status)
+		{
+			qca_ar8327_phy_write(0, 5, 0x0, 0x005b);/*fix phy psgmii RX 20bit*/
+			qca_ar8327_phy_write(0, 5, 0x0, 0x001b);/*reset phy psgmii*/
+			qca_ar8327_phy_write(0, 5, 0x0, 0x005b);/*release reset phy psgmii*/
+			mdelay(100);
+			qca_ar8327_phy_write(0, 5, 0x1a, 0x2230);/*freeze phy psgmii RX CDR*/
+
+			#if defined(CONFIG_OF) && (LINUX_VERSION_CODE >= KERNEL_VERSION(3,14,0))
+			ssdk_ess_reset();
+			#endif
+
+			qca_ar8327_phy_write(0, 5, 0x1a, 0x3230);/*relesae phy psgmii RX CDR*/
+			qca_ar8327_phy_write(0, 5, 0x0, 0x005f);/*release phy psgmii RX 20bit*/
+			mdelay(200);
+		}
+		else
+		{
+		                break;
+		}
+	}
+
+#if 1
+	if (i>=100)
+		printk("PSGMII cannot recover\n");
+	else
+		printk("PSGMII recovered after %d times reset\n",i);
+#endif
+	/*configuration recover*/
+	/*packet number*/
+	qca_phy_mmd_write(0, 0x1f, 7, 0x8021, 0x0);
+	/*disable check*/
+	qca_phy_mmd_write(0, 0x1f, 7, 0x8029, 0x0);
+	/*disable traffic*/
+	qca_phy_mmd_write(0, 0x1f, 7, 0x8020, 0x0);
+}
+
+
+void clear_self_test_config()
+{
+	int i = 0, phy = 0;
+	u32 value = 0;
+	/* disable EEE */
+	qca_phy_mmd_write(0, 0x1f, 0x7,  0x3c, 0x0);
+
+	/*disable phy internal loopback*/
+	qca_ar8327_phy_write(0, 0x1f, 0x10, 0x6860);
+	qca_ar8327_phy_write(0, 0x1f, 0x0, 0x9040);
+
+	for(phy = 0; phy < 5; phy++)
+	{
+		/*disable mac loop back*/
+		value = readl(hw_addr+0x66c+phy*0xc);
+		writel((value&(~(1<<21))), (hw_addr+0x66c+phy*0xc));
+		/*diable phy mdio broadcast write*/
+		qca_phy_mmd_write(0, phy, 7, 0x8028, 0x001f);
+	}
+}
 
 sw_error_t
 ssdk_init(a_uint32_t dev_id, ssdk_init_cfg * cfg)
@@ -1564,10 +1777,20 @@
     rv = hsl_dev_init(dev_id, cfg);
 #else
     rv = fal_init(dev_id, cfg);
+    if (rv != SW_OK)
+	printk("ssdk fal init failed \r\n");
 #endif
 #endif
+
+    ssdk_phy_init(cfg);
+
+	if (cfg->chip_type == CHIP_DESS)
+		ssdk_psgmii_self_test();
     rv =  ssdk_switch_init(dev_id);
-	ssdk_phy_init(cfg);
+    if (rv != SW_OK)
+	printk("ssdk switch init failed \r\n");
+	if (cfg->chip_type == CHIP_DESS)
+		clear_self_test_config();
 
     return rv;
 }
@@ -1647,6 +1870,35 @@
         mdiobus_write(bus, phy_addr, QCA_MII_MMD_DATA, data);
 }
 
+void qca_phy_mmd_write(u32 dev_id, u32 phy_id,
+                     u16 mmd_num, u16 reg_id, u16 reg_val)
+{
+	qca_ar8327_phy_write(dev_id, phy_id,
+			QCA_MII_MMD_ADDR, mmd_num);
+	qca_ar8327_phy_write(dev_id, phy_id,
+			QCA_MII_MMD_DATA, reg_id);
+	qca_ar8327_phy_write(dev_id, phy_id,
+			QCA_MII_MMD_ADDR,
+			0x4000 | mmd_num);
+	qca_ar8327_phy_write(dev_id, phy_id,
+		QCA_MII_MMD_DATA, reg_val);
+}
+
+u16 qca_phy_mmd_read(u32 dev_id, u32 phy_id,
+		u16 mmd_num, u16 reg_id)
+{
+	u16 value = 0;
+	qca_ar8327_phy_write(dev_id, phy_id,
+			QCA_MII_MMD_ADDR, mmd_num);
+	qca_ar8327_phy_write(dev_id, phy_id,
+			QCA_MII_MMD_DATA, reg_id);
+	qca_ar8327_phy_write(dev_id, phy_id,
+			QCA_MII_MMD_ADDR,
+			0x4000 | mmd_num);
+	qca_ar8327_phy_read(dev_id, phy_id,
+			QCA_MII_MMD_DATA, &value);
+	return value;
+}
 
 uint32_t
 qca_switch_reg_read(a_uint32_t dev_id, a_uint32_t reg_addr, a_uint8_t * reg_data, a_uint32_t len)
@@ -1719,20 +1971,9 @@
 }
 
 
-void switch_port_enable()
+void switch_cpuport_enable()
 {
-	a_uint32_t value = 0x4e;
-	a_uint8_t reg_value[] = {0};
-
-	aos_mem_copy(reg_value, &value, sizeof(a_uint32_t));
-	qca_switch_reg_write(0, 0x7c, &reg_value, 4 );
-/*
-	qca_switch_reg_write(0, 0x80, &reg_value, 4 );
-	qca_switch_reg_write(0, 0x84, &reg_value, 4 );
-	qca_switch_reg_write(0, 0x88, &reg_value, 4 );
-	qca_switch_reg_write(0, 0x8c, (a_uint8_t *)&reg_value, 4 );
-	qca_switch_reg_write(0, 0x90, (a_uint8_t *)&reg_value, 4 );
-*/
+	writel(0x7e, hw_addr + 0x7c);
 }
 
 #if defined(CONFIG_OF) && (LINUX_VERSION_CODE >= KERNEL_VERSION(3,14,0))
@@ -1888,17 +2129,7 @@
 	reg_value = 0x2200;
 	qca_psgmii_reg_write(0, DESS_PSGMII_MODE_CONTROL,
 						(a_uint8_t *)&reg_value, 4);
-	reg_value = 0x2803;
-	qca_psgmii_reg_write(0, DESS_PSGMII_PLL_VCO_RELATED_CONTROL_1,
-						(a_uint8_t *)&reg_value, 4);
-	reg_value = 0x4ADA;
-	qca_psgmii_reg_write(0, DESS_PSGMII_VCO_CALIBRATION_CONTROL_1,
-						(a_uint8_t *)&reg_value, 4);
-	udelay(1000);
-	reg_value = 0xADA;
-	qca_psgmii_reg_write(0, DESS_PSGMII_VCO_CALIBRATION_CONTROL_1,
-						(a_uint8_t *)&reg_value, 4);
-	udelay(1000);
+
 	return 0;
 }
 
@@ -1928,6 +2159,23 @@
 	return ssdk_rfs_ipct_rule_set(src, dst, sport, dport,
 							proto, rxq_index, action);
 }
+
+static int ssdk_dev_event(struct notifier_block *this, unsigned long event, void *ptr)
+{
+	struct net_device *dev = netdev_notifier_info_to_dev(ptr);
+
+	switch (event) {
+		case NETDEV_UP:
+			if (strstr(dev->name, "eth")) {
+				if (dev->netdev_ops && dev->netdev_ops->ndo_register_rfs_filter) {
+					dev->netdev_ops->ndo_register_rfs_filter(dev,
+						ssdk_netdev_rfs_cb);
+				}
+			}
+			break;
+	}
+	return NOTIFY_DONE;
+}
 #endif
 int ssdk_intf_search(
 	fal_intf_mac_entry_t *exist_entry, int num,
@@ -2067,7 +2315,34 @@
 	return NOTIFY_DONE;
 }
 #endif
+#if defined(CONFIG_OF) && (LINUX_VERSION_CODE >= KERNEL_VERSION(3,14,0))
+char ssdk_driver_name[] = "ess_ssdk";
 
+static int ssdk_probe(struct platform_device *pdev)
+{
+	ess_rst = devm_reset_control_get(&pdev->dev, "ess_rst");
+	reset_control_assert(ess_rst);
+	mdelay(10);
+	reset_control_deassert(ess_rst);
+	mdelay(100);
+	printk("reset ok in probe!\n");
+	return 0;
+}
+
+static const struct of_device_id ssdk_of_mtable[] = {
+        {.compatible = "qcom,ess-switch" },
+        {}
+};
+
+static struct platform_driver ssdk_driver = {
+        .driver = {
+                .name    = ssdk_driver_name,
+                .owner   = THIS_MODULE,
+                .of_match_table = ssdk_of_mtable,
+        },
+        .probe    = ssdk_probe,
+};
+#endif
 static int __init
 regi_init(void)
 {
@@ -2077,11 +2352,11 @@
 	ssdk_dt_global.switch_reg_access_mode = HSL_REG_MDIO;
 	ssdk_dt_global.psgmii_reg_access_mode = HSL_REG_MDIO;
 	a_uint8_t chip_version = 0;
-	#ifdef IN_RFS
-	#if defined(CONFIG_RFS_ACCEL)
-	struct net_device *rfs_net = NULL;
+	#if defined(CONFIG_OF) && (LINUX_VERSION_CODE >= KERNEL_VERSION(3,14,0))
+	struct device dev;
+	struct reset_control *ess_rst = NULL;
 	#endif
-
+	#ifdef IN_RFS
 	memset(&rfs_dev, 0, sizeof(rfs_dev));
 	#endif
 
@@ -2097,6 +2372,15 @@
 
 	memset(&chip_spec_cfg, 0, sizeof(garuda_init_spec_cfg));
 
+#if defined(CONFIG_OF) && (LINUX_VERSION_CODE >= KERNEL_VERSION(3,14,0))
+	if(ssdk_dt_global.switch_reg_access_mode == HSL_REG_LOCAL_BUS) {
+		dev.of_node=of_find_node_by_name(NULL, "ess-switch");
+
+		platform_driver_register(&ssdk_driver);
+	}
+#endif
+
+
 	if(ssdk_dt_global.switch_reg_access_mode == HSL_REG_MDIO)
 		cfg.reg_mode = HSL_MDIO;
 	else if(ssdk_dt_global.switch_reg_access_mode == HSL_REG_LOCAL_BUS)
@@ -2146,22 +2430,9 @@
 	rfs_dev.ip6_rule_cb = ssdk_rfs_ip6_rule_set;
 	rfs_ess_device_register(&rfs_dev);
 	#if defined(CONFIG_RFS_ACCEL)
-	rfs_net = dev_get_by_name(&init_net, "eth0");
-	if(rfs_net) {
-		if(rfs_net->netdev_ops) {
-			if(rfs_net->netdev_ops->ndo_register_rfs_filter)
-				rfs_net->netdev_ops->ndo_register_rfs_filter(rfs_net,
-					ssdk_netdev_rfs_cb);
-		}
-	}
-	rfs_net = dev_get_by_name(&init_net, "eth1");
-        if(rfs_net) {
-                if(rfs_net->netdev_ops) {
-                        if(rfs_net->netdev_ops->ndo_register_rfs_filter)
-                                rfs_net->netdev_ops->ndo_register_rfs_filter(rfs_net,
-                                        ssdk_netdev_rfs_cb);
-                }
-        }
+	ssdk_dev_notifier.notifier_call = ssdk_dev_event;
+	ssdk_dev_notifier.priority = 1;
+	register_netdevice_notifier(&ssdk_dev_notifier);
 	#endif
 	ssdk_inet_notifier.notifier_call = ssdk_inet_event;
 	ssdk_inet_notifier.priority = 1;
@@ -2169,7 +2440,7 @@
 
 #endif
 		/* Enable port temprarily, will remove the code when phy board is ok. */
-		switch_port_enable();
+		switch_cpuport_enable();
 	}
 
 out:
@@ -2199,6 +2470,9 @@
 #ifdef IN_RFS
 		rfs_ess_device_unregister(&rfs_dev);
 	unregister_inetaddr_notifier(&ssdk_inet_notifier);
+	#if defined(CONFIG_RFS_ACCEL)
+	unregister_netdevice_notifier(&ssdk_dev_notifier);
+	#endif
 #endif
 
 	}
diff --git a/src/ref/ref_misc.c b/src/ref/ref_misc.c
index f0dd61a..f715742 100755
--- a/src/ref/ref_misc.c
+++ b/src/ref/ref_misc.c
@@ -114,16 +114,18 @@
     memset(priv->vlan_tagged, 0, sizeof(a_uint8_t) * AR8327_MAX_VLANS);
     memset(priv->pvid, 0, sizeof(a_uint16_t) * AR8327_NUM_PORTS);
 
-    /*for (i = 0; i < AR8327_MAX_VLANS; i++)*/
-    /*    priv->vlan_id[i] = i;*/
-#ifndef BOARD_AR71XX
+	/*for (i = 0; i < AR8327_MAX_VLANS; i++)*/
+	/*    priv->vlan_id[i] = i;*/
+	#ifndef BOARD_AR71XX
+	if (priv->version == QCA_VER_AR8327 ||
+		priv->version == QCA_VER_AR8337) {
+		qca_ar8327_phy_disable();
+		msleep(1000);
+	/* init switch, not necessary for dess??*/
+	rv += ssdk_switch_init(0);
 
-	qca_ar8327_phy_disable();
-	msleep(1000);
-
-#endif
-    /* init switch */
-    rv += ssdk_switch_init(0);
+	}
+	#endif
 
     mutex_unlock(&priv->reg_mutex);
 
@@ -136,13 +138,19 @@
 		qca_ar8327_port_init(priv, i);
 	}
 	#endif
-	fal_port_link_forcemode_set(0, 1, A_FALSE);
-	fal_port_link_forcemode_set(0, 2, A_FALSE);
-	fal_port_link_forcemode_set(0, 3, A_FALSE);
-	fal_port_link_forcemode_set(0, 4, A_FALSE);
-	fal_port_link_forcemode_set(0, 5, A_FALSE);
-	qca_ar8327_phy_enable(priv);
+	if (priv->version == QCA_VER_AR8327 ||
+		priv->version == QCA_VER_AR8337) {
+		fal_port_link_forcemode_set(0, 1, A_FALSE);
+		fal_port_link_forcemode_set(0, 2, A_FALSE);
+		fal_port_link_forcemode_set(0, 3, A_FALSE);
+		fal_port_link_forcemode_set(0, 4, A_FALSE);
+		fal_port_link_forcemode_set(0, 5, A_FALSE);
+		qca_ar8327_phy_enable(priv);
+	}
 	#endif
-    return rv;
+	fal_port_rxmac_status_set(0, 0, A_TRUE);
+	fal_port_txmac_status_set(0, 0, A_TRUE);
+
+	return rv;
 }