[qca-ssdk]: merge hawkeye ssdk init codes to master branch

Change-Id: Idee7156e3e16b1f0052b5a07a0d3c34e1fe4a4d8
Signed-off-by: mingxinh <mingxinh@codeaurora.org>
diff --git a/include/init/ssdk_init.h b/include/init/ssdk_init.h
index e94d63f..c10c071 100755
--- a/include/init/ssdk_init.h
+++ b/include/init/ssdk_init.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012, 2015, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2012, 2015-2017, The Linux Foundation. All rights reserved.
  * Permission to use, copy, modify, and/or distribute this software for
  * any purpose with or without fee is hereby granted, provided that the
  * above copyright notice and this permission notice appear in all copies.
@@ -78,7 +78,11 @@
 	PORT_WRAPPER_SGMII0_RGMII4,
 	PORT_WRAPPER_SGMII1_RGMII4,
 	PORT_WRAPPER_SGMII4_RGMII4,
-	PORT_WRAPPER_MAX
+	PORT_WRAPPER_QSGMII,
+	PORT_WRAPPER_SGMII_PLUS,
+	PORT_WRAPPER_USXGMII,
+	PORT_WRAPPER_XFI,
+	PORT_WRAPPER_MAX = 0xFF
 };
 
     typedef struct
@@ -156,6 +160,8 @@
 	a_uint32_t led_source_num;
 	led_source_cfg_t led_source_cfg[15];
 	a_uint32_t      phy_id;
+	a_uint32_t      mac_mode1;
+	a_uint32_t      mac_mode2;
 } ssdk_init_cfg;
 
 	typedef struct
@@ -170,6 +176,12 @@
 		hsl_reg_mode psgmii_reg_access_mode;
 		struct clk *ess_clk;
 		a_uint32_t      mac_mode;
+		a_uint32_t      mac_mode1;
+		a_uint32_t      mac_mode2;
+		a_uint32_t uniphyreg_base_addr;
+		a_uint32_t uniphyreg_size;
+		a_uint8_t *uniphy_access_mode;
+		hsl_reg_mode uniphy_reg_access_mode;
 	} ssdk_dt_cfg;
 
 typedef struct phy_identification {
@@ -279,22 +291,47 @@
         ssdk_init_cfg init_cfg;
     } ssdk_cfg_t;
 
-    sw_error_t
-    ssdk_init(a_uint32_t dev_id, ssdk_init_cfg *cfg);
+sw_error_t
+ssdk_init(a_uint32_t dev_id, ssdk_init_cfg *cfg);
 
-sw_error_t qca_ar8327_phy_read(a_uint32_t dev_id, a_uint32_t phy_addr,
+sw_error_t
+ssdk_hsl_access_mode_set(a_uint32_t dev_id, hsl_access_mode reg_mode);
+
+a_uint32_t ssdk_dt_global_get_mac_mode(void);
+
+uint32_t
+qca_hppe_gcc_speed_clock1_reg_read(a_uint32_t dev_id, a_uint32_t reg_addr,
+				a_uint8_t * reg_data, a_uint32_t len);
+
+uint32_t
+qca_hppe_gcc_speed_clock1_reg_write(a_uint32_t dev_id, a_uint32_t reg_addr,
+				a_uint8_t * reg_data, a_uint32_t len);
+
+uint32_t
+qca_hppe_gcc_speed_clock2_reg_read(a_uint32_t dev_id, a_uint32_t reg_addr,
+				a_uint8_t * reg_data, a_uint32_t len);
+
+uint32_t
+qca_hppe_gcc_speed_clock2_reg_write(a_uint32_t dev_id, a_uint32_t reg_addr,
+				a_uint8_t * reg_data, a_uint32_t len);
+
+uint32_t
+qca_hppe_uniphy_reg_write(a_uint32_t dev_id, a_uint32_t uniphy_index,
+				a_uint32_t reg_addr, a_uint8_t * reg_data, a_uint32_t len);
+
+uint32_t
+qca_hppe_uniphy_reg_read(a_uint32_t dev_id, a_uint32_t uniphy_index,
+				a_uint32_t reg_addr, a_uint8_t * reg_data, a_uint32_t len);
+sw_error_t
+qca_hppe_xgphy_read(a_uint32_t dev_id, a_uint32_t phy_addr,
                            a_uint32_t reg, a_uint16_t* data);
-sw_error_t qca_ar8327_phy_write(a_uint32_t dev_id, a_uint32_t phy_addr,
-                            a_uint32_t reg, a_uint16_t data);
 
-sw_error_t qca_switch_reg_read(a_uint32_t dev_id, a_uint32_t reg_addr,
-			a_uint8_t * reg_data, a_uint32_t len);
-sw_error_t qca_switch_reg_write(a_uint32_t dev_id, a_uint32_t reg_addr,
-			a_uint8_t * reg_data, a_uint32_t len);
+sw_error_t
+qca_hppe_xgphy_write(a_uint32_t dev_id, a_uint32_t phy_addr,
+                           a_uint32_t reg, a_uint16_t data);
 
-    sw_error_t
-    ssdk_hsl_access_mode_set(a_uint32_t dev_id, hsl_access_mode reg_mode);
-	a_uint32_t ssdk_dt_global_get_mac_mode(void);
+a_uint32_t
+qca_hppe_port_mac_type_get(a_uint32_t dev_id, a_uint32_t port_id);
 
 #ifdef __cplusplus
 }
diff --git a/include/init/ssdk_plat.h b/include/init/ssdk_plat.h
index e81f1d4..fd7ac50 100755
--- a/include/init/ssdk_plat.h
+++ b/include/init/ssdk_plat.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012, 2014-2015, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2012, 2014-2015, 2017, The Linux Foundation. All rights reserved.
  * Permission to use, copy, modify, and/or distribute this software for
  * any purpose with or without fee is hereby granted, provided that the
  * above copyright notice and this permission notice appear in all copies.
@@ -101,7 +101,7 @@
 
 #define AR8327_REG_MODULE_EN  0x30
 #define   AR8327_REG_MODULE_EN_QM_ERR	BIT(8)
-#define   AR8327_REG_MODULE_EN_LOOKUP_ERR	BIT(9)
+#define   AR8327_REG_MODULE_EN_LOOKUP_ERR      BIT(9)
 
 #define AR8327_REG_MAC_SFT_RST		0x68
 
@@ -157,7 +157,9 @@
 	QCA_VER_AR8236 = 0x03,
 	QCA_VER_AR8316 = 0x10,
 	QCA_VER_AR8327 = 0x12,
-	QCA_VER_AR8337 = 0x13
+	QCA_VER_AR8337 = 0x13,
+	QCA_VER_DESS = 0x14,
+	QCA_VER_HPPE = 0x15
 };
 
 /*poll mib per 120secs*/
@@ -189,7 +191,7 @@
 	a_uint8_t revision;
 	a_uint32_t (*mii_read)(a_uint32_t reg);
 	void (*mii_write)(a_uint32_t reg, a_uint32_t val);
-        void (*phy_dbg_write)(a_uint32_t dev_id, a_uint32_t phy_addr,
+    void (*phy_dbg_write)(a_uint32_t dev_id, a_uint32_t phy_addr,
                         a_uint16_t dbg_addr, a_uint16_t dbg_data);
 	void (*phy_dbg_read)(a_uint32_t dev_id, a_uint32_t phy_addr,
                         a_uint16_t dbg_addr, a_uint16_t *dbg_data);
@@ -220,7 +222,9 @@
     a_uint8_t  vlan_table[AR8327_MAX_VLANS];
     a_uint8_t  vlan_tagged[AR8327_MAX_VLANS];
     a_uint16_t pvid[AR8327_NUM_PORTS];
-
+	u8 __iomem *hw_addr;
+	u8 __iomem *psgmii_hw_addr;
+	int phy_address[5];
 };
 
 struct ipq40xx_mdio_data {
@@ -238,6 +242,9 @@
 void
 qca_ar8216_mii_write(a_uint32_t reg, a_uint32_t val);
 sw_error_t
+qca_ar8327_phy_read(a_uint32_t dev_id, a_uint32_t phy_addr,
+			a_uint32_t reg, a_uint16_t* data);
+sw_error_t
 qca_ar8327_phy_write(a_uint32_t dev_id, a_uint32_t phy_addr,
                             a_uint32_t reg, a_uint16_t data);
 void
@@ -258,4 +265,23 @@
 qca_phy_mmd_read(u32 dev_id, u32 phy_id,
 		u16 mmd_num, u16 reg_id);
 
+sw_error_t
+qca_switch_reg_read(a_uint32_t dev_id, a_uint32_t reg_addr,
+			a_uint8_t * reg_data, a_uint32_t len);
+
+sw_error_t
+qca_switch_reg_write(a_uint32_t dev_id, a_uint32_t reg_addr,
+			a_uint8_t * reg_data, a_uint32_t len);
+
+sw_error_t
+qca_psgmii_reg_read(a_uint32_t dev_id, a_uint32_t reg_addr,
+			a_uint8_t * reg_data, a_uint32_t len);
+
+sw_error_t
+qca_psgmii_reg_write(a_uint32_t dev_id, a_uint32_t reg_addr,
+			a_uint8_t * reg_data, a_uint32_t len);
+
+int ssdk_plat_init(ssdk_init_cfg *cfg);
+void ssdk_plat_exit(void);
+
 #endif
diff --git a/include/ref/ref_vsi.h b/include/ref/ref_vsi.h
index 6bf28d3..3509388 100755
--- a/include/ref/ref_vsi.h
+++ b/include/ref/ref_vsi.h
@@ -68,6 +68,6 @@
 sw_error_t ppe_vsi_alloc(a_uint32_t dev_id, a_uint32_t *vsi);
 sw_error_t ppe_vsi_free(a_uint32_t dev_id, a_uint32_t vsi_id);
 sw_error_t ppe_vsi_tbl_dump(a_uint32_t dev_id);
-
+sw_error_t ppe_vsi_init(a_uint32_t dev_id);
 #endif
 
diff --git a/src/fal/fal_init.c b/src/fal/fal_init.c
index cb0aa4a..82415dd 100755
--- a/src/fal/fal_init.c
+++ b/src/fal/fal_init.c
@@ -44,12 +44,10 @@
     rv = hsl_dev_init(dev_id, cfg);
     SW_RTN_ON_ERROR(rv);
 
-	#ifndef ESS_ONLY_FPGA
 #ifdef IN_VLAN
     rv = fal_vlan_init(dev_id);
     SW_RTN_ON_ERROR(rv);
 #endif
-	#endif
 
     rv = adpt_init(dev_id, cfg);
     SW_RTN_ON_ERROR(rv);
diff --git a/src/hsl/hppe/hppe_reg_access.c b/src/hsl/hppe/hppe_reg_access.c
index 9b4ca5f..ae18f63 100755
--- a/src/hsl/hppe/hppe_reg_access.c
+++ b/src/hsl/hppe/hppe_reg_access.c
@@ -19,6 +19,25 @@
  */
 #include "sw.h"
 #include "ssdk_init.h"
+#include <linux/kconfig.h>
+#include <linux/version.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/phy.h>
+#include <linux/platform_device.h>
+#include <linux/types.h>
+#include <generated/autoconf.h>
+#if defined(CONFIG_OF) && (LINUX_VERSION_CODE >= KERNEL_VERSION(3,14,0))
+#include <linux/switch.h>
+#else
+#include <net/switch.h>
+#include <linux/ar8216_platform.h>
+#endif
+#include <linux/delay.h>
+#include <linux/phy.h>
+#include <linux/netdevice.h>
+#include "ssdk_plat.h"
+#include <linux/string.h>
 
 sw_error_t hppe_reg_get(a_uint32_t dev_id, a_uint32_t reg_addr, a_uint32_t *val)
 {
@@ -52,17 +71,13 @@
 
 sw_error_t hppe_uniphy_reg_get(a_uint32_t dev_id, a_uint32_t reg_addr, a_uint32_t index, a_uint32_t *val)
 {
-#if 0
 	qca_hppe_uniphy_reg_read(dev_id, index, reg_addr, (a_uint8_t *)val, 4);
-#endif
 	return SW_OK;
 }
 
 sw_error_t hppe_uniphy_reg_set(a_uint32_t dev_id, a_uint32_t reg_addr, a_uint32_t index, a_uint32_t val)
 {
-#if 0
 	qca_hppe_uniphy_reg_write(dev_id, index, reg_addr, (a_uint8_t *)&val, 4);
-#endif
 	return SW_OK;
 }
 
diff --git a/src/init/ssdk_init.c b/src/init/ssdk_init.c
index 9c898ef..e9d05bb 100755
--- a/src/init/ssdk_init.c
+++ b/src/init/ssdk_init.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012, 2014-2015, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2012, 2014-2017, The Linux Foundation. All rights reserved.
  * Permission to use, copy, modify, and/or distribute this software for
  * any purpose with or without fee is hereby granted, provided that the
  * above copyright notice and this permission notice appear in all copies.
@@ -16,33 +16,7 @@
 #include "sw.h"
 #include "ssdk_init.h"
 #include "fal_init.h"
-#ifdef IN_MISC
-#include "fal_misc.h"
-#endif
-#ifdef IN_MIB
-#include "fal_mib.h"
-#endif
-#ifdef IN_PORTCONTROL
-#include "fal_port_ctrl.h"
-#endif
-#ifdef IN_PORTVLAN
-#include "fal_portvlan.h"
-#endif
-#ifdef IN_FDB
-#include "fal_fdb.h"
-#endif
-#ifdef IN_STP
-#include "fal_stp.h"
-#endif
-#ifdef IN_IGMP
-#include "fal_igmp.h"
-#endif
-#ifdef IN_QOS
-#include "fal_qos.h"
-#endif
-#ifdef IN_LED
-#include "fal_led.h"
-#endif
+#include "fal.h"
 #include "hsl.h"
 #include "hsl_dev.h"
 #include "ssdk_init.h"
@@ -93,6 +67,7 @@
 #include "ref_port_ctrl.h"
 #include "ref_misc.h"
 #include "ref_uci.h"
+#include "ref_vsi.h"
 #include "shell.h"
 #ifdef BOARD_AR71XX
 #include "ssdk_uci.h"
@@ -116,11 +91,12 @@
 #include "fal_rfs.h"
 #endif
 #endif
+#include "hppe_reg_access.h"
+#include "hppe_fdb_reg.h"
+#include "hppe_fdb.h"
+#include "hppe_init.h"
 
-#define ISIS_CHIP_ID 0x18
-#define ISIS_CHIP_REG 0
-#define SHIVA_CHIP_ID 0x1f
-#define SHIVA_CHIP_REG 0x10
+#include "adpt.h"
 
 #ifdef IN_RFS
 struct rfs_device rfs_dev;
@@ -140,21 +116,17 @@
 #define QCA_QM_ITEM_NUMBER 41
 #define QCA_RGMII_WORK_DELAY	1000
 
-/*
- * Using ISIS's address as default
-  */
-static int switch_chip_id = ISIS_CHIP_ID;
-static int switch_chip_reg = ISIS_CHIP_REG;
 ssdk_dt_cfg ssdk_dt_global = {0};
-u8  __iomem      *hw_addr = NULL;
-u8  __iomem      *psgmii_hw_addr = NULL;
+void __iomem *hppe_uniphy_addr = NULL;
+void __iomem *gcc_uniphy_base = NULL;
+void __iomem *gcc_hppe_clock_config1_base = NULL;
+void __iomem *gcc_hppe_clock_config2_base = NULL;
 
 a_uint32_t ssdk_dt_global_get_mac_mode(void)
 {
 	return ssdk_dt_global.mac_mode;
 }
 
-static struct mutex switch_mdio_lock;
 phy_identification_t phy_array[] =
 {
 	#ifdef IN_MALIBU_PHY
@@ -351,6 +323,7 @@
 	#ifdef IN_MIB
 	/* Enable MIB counters */
 	fal_mib_status_set(dev_id, A_TRUE);
+	fal_mib_cpukeep_set(dev_id, A_FALSE);
 	#endif
 	#ifdef IN_IGMP
 	fal_igmp_mld_rp_set(dev_id, 0);
@@ -626,11 +599,6 @@
 	/*After switch software reset, need disable all ports' MAC with 1000M FULL*/
 	qca_switch_set_mac_force(priv);
 
-	value = priv->mii_read(AR8327_REG_MODULE_EN);
-	value &= ~AR8327_REG_MODULE_EN_QM_ERR;
-	value &= ~AR8327_REG_MODULE_EN_LOOKUP_ERR;
-	priv->mii_write(AR8327_REG_MODULE_EN, value);
-
 	/* Configure switch register from DT information */
 	paddr = of_get_property(np, "qca,ar8327-initvals", &len);
 	if (!paddr || len < (2 * sizeof(*paddr))) {
@@ -937,8 +905,9 @@
 {
 	struct ar8327_platform_data *plat_data;
 	a_uint32_t i = 0;
+#ifndef BOARD_AR71XX
 	a_uint32_t value = 0;
-
+#endif
 	plat_data = priv->phy->dev.platform_data;
 	if (plat_data == NULL) {
 		return -EINVAL;
@@ -963,11 +932,6 @@
 	/*After switch software reset, need disable all ports' MAC with 1000M FULL*/
 	qca_switch_set_mac_force(priv);
 
-	value = priv->mii_read(AR8327_REG_MODULE_EN);
-	value &= ~AR8327_REG_MODULE_EN_QM_ERR;
-	value &= ~AR8327_REG_MODULE_EN_LOOKUP_ERR;
-	priv->mii_write(AR8327_REG_MODULE_EN, value);
-
 	qca_ar8327_set_pad_cfg(priv, plat_data);
 
 	qca_switch_init(0);
@@ -1183,10 +1147,13 @@
 int
 qm_err_check_work_start(struct qca_phy_priv *priv)
 {
+	if (priv->version == QCA_VER_HPPE)
+		return 0;
+
 	/*Only valid for S17c chip*/
 	if (priv->version != QCA_VER_AR8337 &&
 		priv->version != QCA_VER_AR8327 &&
-		priv->version != 0x14)
+		priv->version != QCA_VER_DESS)
 		return -1;
 
 	mutex_init(&priv->qm_lock);
@@ -1210,7 +1177,7 @@
 	/*Only valid for S17c chip*/
 	if (priv->version != QCA_VER_AR8337 &&
 		priv->version != QCA_VER_AR8327 &&
-		priv->version != 0x14) return;
+		priv->version != QCA_VER_DESS) return;
 
 	cancel_delayed_work_sync(&priv->qm_dwork);
 }
@@ -1276,7 +1243,7 @@
 {
 	struct qca_phy_priv *priv = pdev->priv;
 	struct switch_dev *sw_dev;
-	int ret;
+	int ret = 0;
 
 	if (pdev->addr != 0) {
         pdev->supported |= SUPPORTED_1000baseT_Full;
@@ -1334,7 +1301,7 @@
 
 struct qca_phy_priv *qca_phy_priv_global;
 
-#ifdef DESS
+#if defined(DESS) || defined(HPPE)
 static int ssdk_switch_register(void)
 {
 	struct switch_dev *sw_dev;
@@ -1342,11 +1309,7 @@
 	int ret = 0;
 	a_uint32_t chip_id = 0;
 
-	priv = kzalloc(sizeof(struct qca_phy_priv), GFP_KERNEL);
-	if (priv == NULL) {
-		return -ENOMEM;
-	}
-	qca_phy_priv_global = priv;
+	priv = qca_phy_priv_global;
 
 	priv->mii_read = qca_ar8216_mii_read;
 	priv->mii_write = qca_ar8216_mii_write;
@@ -1358,7 +1321,7 @@
 	if (fal_reg_get(0, 0, (a_uint8_t *)&chip_id, 4) == SW_OK) {
 		priv->version = ((chip_id >> 8) & 0xff);
 		priv->revision = (chip_id & 0xff);
-		printk("Dakota Chip version 0x%02x%02x\n", priv->version, priv->revision);
+		printk("Chip version 0x%02x%02x\n", priv->version, priv->revision);
 	}
 
 	mutex_init(&priv->reg_mutex);
@@ -1413,7 +1376,6 @@
 	qca_phy_mib_work_stop(qca_phy_priv_global);
 	qm_err_check_work_stop(qca_phy_priv_global);
 	unregister_switch(&qca_phy_priv_global->sw_dev);
-	kfree(qca_phy_priv_global);
 	return 0;
 }
 #endif
@@ -1521,433 +1483,6 @@
 	.driver		= { .owner = THIS_MODULE },
 };
 
-#if defined(CONFIG_OF) && (LINUX_VERSION_CODE >= KERNEL_VERSION(3,14,0))
-struct ag71xx_mdio {
-	struct mii_bus		*mii_bus;
-	int			mii_irq[PHY_MAX_ADDR];
-	void __iomem		*mdio_base;
-};
-#endif
-static struct mii_bus *miibus = NULL;
-static int phy_address[5] = {0,1,2,3,4};
-
-#ifdef BOARD_IPQ806X
-#define IPQ806X_MDIO_BUS_NAME			"mdio-gpio"
-#endif
-
-#ifdef BOARD_AR71XX
-#define IPQ806X_MDIO_BUS_NAME			"ag71xx-mdio"
-#endif
-#define MDIO_BUS_0						0
-#define MDIO_BUS_1						1
-#define IPQ806X_MDIO_BUS_NUM			MDIO_BUS_0
-
-static inline void
-split_addr(uint32_t regaddr, uint16_t *r1, uint16_t *r2, uint16_t *page)
-{
-	regaddr >>= 1;
-	*r1 = regaddr & 0x1e;
-
-	regaddr >>= 5;
-	*r2 = regaddr & 0x7;
-
-	regaddr >>= 3;
-	*page = regaddr & 0x3ff;
-}
-
-a_uint32_t
-qca_ar8216_mii_read(a_uint32_t reg)
-{
-        struct mii_bus *bus = miibus;
-        uint16_t r1, r2, page;
-        uint16_t lo, hi;
-
-        split_addr((uint32_t) reg, &r1, &r2, &page);
-        mutex_lock(&switch_mdio_lock);
-        mdiobus_write(bus, switch_chip_id, switch_chip_reg, page);
-	udelay(100);
-        lo = mdiobus_read(bus, 0x10 | r2, r1);
-        hi = mdiobus_read(bus, 0x10 | r2, r1 + 1);
-        mutex_unlock(&switch_mdio_lock);
-        return (hi << 16) | lo;
-}
-
-void
-qca_ar8216_mii_write(a_uint32_t reg, a_uint32_t val)
-{
-        struct mii_bus *bus = miibus;
-        uint16_t r1, r2, r3;
-        uint16_t lo, hi;
-
-        split_addr((a_uint32_t) reg, &r1, &r2, &r3);
-        lo = val & 0xffff;
-        hi = (a_uint16_t) (val >> 16);
-
-        mutex_lock(&switch_mdio_lock);
-        mdiobus_write(bus, switch_chip_id, switch_chip_reg, r3);
-	udelay(100);
-        if(SSDK_CURRENT_CHIP_TYPE != CHIP_SHIVA) {
-            mdiobus_write(bus, 0x10 | r2, r1, lo);
-            mdiobus_write(bus, 0x10 | r2, r1 + 1, hi);
-        } else {
-            mdiobus_write(bus, 0x10 | r2, r1 + 1, hi);
-            mdiobus_write(bus, 0x10 | r2, r1, lo);
-        }
-        mutex_unlock(&switch_mdio_lock);
-}
-
-a_bool_t
-phy_addr_validation_check(a_uint32_t phy_addr)
-{
-
-	if (phy_addr  == SSDK_PHY_BCAST_ID)
-		return A_TRUE;
-	else if ((phy_addr > SSDK_PSGMII_ID) || (phy_addr < SSDK_PHY_MIN_ID))
-		return A_FALSE;
-	else
-		return A_TRUE;
-}
-
-sw_error_t
-qca_ar8327_phy_read(a_uint32_t dev_id, a_uint32_t phy_addr,
-                           a_uint32_t reg, a_uint16_t* data)
-{
-	struct mii_bus *bus = miibus;
-	int phy_dest_addr;
-	if (A_TRUE != phy_addr_validation_check (phy_addr))
-	{
-		return SW_BAD_PARAM;
-	}
-	if (phy_addr == SSDK_PSGMII_ID)
-		phy_dest_addr = phy_address[phy_addr -1] + 1;
-	else if (phy_addr == SSDK_PHY_BCAST_ID)
-		phy_dest_addr = SSDK_PHY_BCAST_ID;
-	else
-		phy_dest_addr = phy_address[phy_addr];
-
-	*data = mdiobus_read(bus, phy_dest_addr, reg);
-	return 0;
-}
-
-sw_error_t
-qca_ar8327_phy_write(a_uint32_t dev_id, a_uint32_t phy_addr,
-                            a_uint32_t reg, a_uint16_t data)
-{
-	struct mii_bus *bus = miibus;
-	int phy_dest_addr;
-	if (A_TRUE != phy_addr_validation_check (phy_addr))
-	{
-		return SW_BAD_PARAM;
-	}
-	if (phy_addr == SSDK_PSGMII_ID)
-		phy_dest_addr = phy_address[phy_addr -1] + 1;
-	else if (phy_addr == SSDK_PHY_BCAST_ID)
-		phy_dest_addr = SSDK_PHY_BCAST_ID;
-	else
-		phy_dest_addr = phy_address[phy_addr];
-
-	mdiobus_write(bus, phy_dest_addr, reg, data);
-	return 0;
-}
-
-void
-qca_ar8327_phy_dbg_write(a_uint32_t dev_id, a_uint32_t phy_addr,
-                                a_uint16_t dbg_addr, a_uint16_t dbg_data)
-{
-	struct mii_bus *bus = miibus;
-	int phy_dest_addr;
-	if (A_TRUE != phy_addr_validation_check (phy_addr))
-	{
-		return ;
-	}
-	if (phy_addr == SSDK_PSGMII_ID)
-		phy_dest_addr = phy_address[phy_addr -1] + 1;
-	else if (phy_addr == SSDK_PHY_BCAST_ID)
-		phy_dest_addr = SSDK_PHY_BCAST_ID;
-	else
-		phy_dest_addr = phy_address[phy_addr];
-
-	mdiobus_write(bus, phy_dest_addr, QCA_MII_DBG_ADDR, dbg_addr);
-	mdiobus_write(bus, phy_dest_addr, QCA_MII_DBG_DATA, dbg_data);
-}
-
-void
-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)
-{
-	struct mii_bus *bus = miibus;
-	int phy_dest_addr;
-	if (A_TRUE != phy_addr_validation_check (phy_addr))
-	{
-		return ;
-	}
-	if (phy_addr == SSDK_PSGMII_ID)
-		phy_dest_addr = phy_address[phy_addr -1] + 1;
-	else if (phy_addr == SSDK_PHY_BCAST_ID)
-		phy_dest_addr = SSDK_PHY_BCAST_ID;
-	else
-		phy_dest_addr = phy_address[phy_addr];
-
-	mdiobus_write(bus, phy_dest_addr, QCA_MII_DBG_ADDR, dbg_addr);
-	*dbg_data = mdiobus_read(bus, phy_dest_addr, QCA_MII_DBG_DATA);
-}
-
-
-void
-qca_ar8327_mmd_write(a_uint32_t dev_id, a_uint32_t phy_addr,
-                          a_uint16_t addr, a_uint16_t data)
-{
-	struct mii_bus *bus = miibus;
-	int phy_dest_addr;
-	if (A_TRUE != phy_addr_validation_check (phy_addr))
-	{
-		return ;
-	}
-	if (phy_addr == SSDK_PSGMII_ID)
-		phy_dest_addr = phy_address[phy_addr -1] + 1;
-	else if (phy_addr == SSDK_PHY_BCAST_ID)
-		phy_dest_addr = SSDK_PHY_BCAST_ID;
-	else
-		phy_dest_addr = phy_address[phy_addr];
-
-	mdiobus_write(bus, phy_dest_addr, QCA_MII_MMD_ADDR, addr);
-	mdiobus_write(bus, phy_dest_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;
-}
-
-sw_error_t
-qca_switch_reg_read(a_uint32_t dev_id, a_uint32_t reg_addr, a_uint8_t * reg_data, a_uint32_t len)
-{
-	uint32_t reg_val = 0;
-
-	if (len != sizeof (a_uint32_t))
-        return SW_BAD_LEN;
-
-	if ((reg_addr%4)!= 0)
-	return SW_BAD_PARAM;
-
-	reg_val = readl(hw_addr + reg_addr);
-
-	aos_mem_copy(reg_data, &reg_val, sizeof (a_uint32_t));
-	return 0;
-}
-
-sw_error_t
-qca_switch_reg_write(a_uint32_t dev_id, a_uint32_t reg_addr, a_uint8_t * reg_data, a_uint32_t len)
-{
-	uint32_t reg_val = 0;
-	if (len != sizeof (a_uint32_t))
-        return SW_BAD_LEN;
-
-	if ((reg_addr%4)!= 0)
-	return SW_BAD_PARAM;
-
-	aos_mem_copy(&reg_val, reg_data, sizeof (a_uint32_t));
-	writel(reg_val, hw_addr + reg_addr);
-	return 0;
-}
-
-sw_error_t
-qca_psgmii_reg_read(a_uint32_t dev_id, a_uint32_t reg_addr, a_uint8_t * reg_data, a_uint32_t len)
-{
-	uint32_t reg_val = 0;
-
-	if (len != sizeof (a_uint32_t))
-        return SW_BAD_LEN;
-
-	if((reg_addr%4)!=0)
-	return SW_BAD_PARAM;
-
-	if (psgmii_hw_addr == NULL)
-		return SW_NOT_SUPPORTED;
-
-	reg_val = readl(psgmii_hw_addr + reg_addr);
-
-	aos_mem_copy(reg_data, &reg_val, sizeof (a_uint32_t));
-	return 0;
-}
-
-sw_error_t
-qca_psgmii_reg_write(a_uint32_t dev_id, a_uint32_t reg_addr, a_uint8_t * reg_data, a_uint32_t len)
-{
-	uint32_t reg_val = 0;
-	if (len != sizeof (a_uint32_t))
-        return SW_BAD_LEN;
-
-	if((reg_addr%4)!=0)
-	return SW_BAD_PARAM;
-
-	if (psgmii_hw_addr == NULL)
-		return SW_NOT_SUPPORTED;
-
-	aos_mem_copy(&reg_val, reg_data, sizeof (a_uint32_t));
-	writel(reg_val, psgmii_hw_addr + reg_addr);
-	return 0;
-}
-
-#ifdef BOARD_AR71XX
-static uint32_t switch_chip_id_adjuest(void)
-{
-	uint32_t chip_version = 0;
-	chip_version = (qca_ar8216_mii_read(0)&0xff00)>>8;
-	if((chip_version !=0) && (chip_version !=0xff))
-		return 0;
-
-	switch_chip_id = SHIVA_CHIP_ID;
-	switch_chip_reg = SHIVA_CHIP_REG;
-
-	chip_version = (qca_ar8216_mii_read(0)&0xff00)>>8;
-	printk("chip_version:0x%x\n", chip_version);
-	return 1;
-}
-#endif
-
-static int miibus_get(void)
-{
-#if defined(CONFIG_OF) && (LINUX_VERSION_CODE >= KERNEL_VERSION(3,14,0))
-	#ifndef BOARD_AR71XX
-	struct device_node *mdio_node = NULL;
-	struct platform_device *mdio_plat = NULL;
-	struct ipq40xx_mdio_data *mdio_data = NULL;
-
-	if(ssdk_dt_global.switch_reg_access_mode == HSL_REG_LOCAL_BUS)
-		mdio_node = of_find_compatible_node(NULL, NULL, "qcom,ipq40xx-mdio");
-	else
-		mdio_node = of_find_compatible_node(NULL, NULL, "virtual,mdio-gpio");
-
-	if (!mdio_node) {
-		printk("No MDIO node found in DTS!\n");
-		return 1;
-	}
-
-	mdio_plat = of_find_device_by_node(mdio_node);
-	if (!mdio_plat) {
-		printk("cannot find platform device from mdio node\n");
-		return 1;
-	}
-
-	if(ssdk_dt_global.switch_reg_access_mode == HSL_REG_LOCAL_BUS)
-	{
-		mdio_data = dev_get_drvdata(&mdio_plat->dev);
-		if (!mdio_data) {
-                	printk("cannot get mdio_data reference from device data\n");
-                	return 1;
-        	}
-		miibus = mdio_data->mii_bus;
-	}
-	else
-		miibus = dev_get_drvdata(&mdio_plat->dev);
-
-	if (!miibus) {
-		printk("cannot get mii bus reference from device data\n");
-		return 1;
-	}
-	#else
-	struct ag71xx_mdio *am;
-	struct device_node *mdio_node = NULL;
-	struct platform_device *mdio_plat = NULL;
-
-	mdio_node = of_find_compatible_node(NULL, NULL, "qca,ag71xx-mdio");
-	if (!mdio_node) {
-		printk("No MDIO node found in DTS!\n");
-		return 1;
-	}
-	mdio_plat = of_find_device_by_node(mdio_node);
-	if (!mdio_plat) {
-		printk("cannot find platform device from mdio node\n");
-		return 1;
-	}
-	am = dev_get_drvdata(&mdio_plat->dev);
-	if (!am) {
-                	printk("cannot get mdio_data reference from device data\n");
-                	return 1;
-	}
-	miibus = am->mii_bus;
-	if (!miibus) {
-		printk("cannot get mii bus reference from device data\n");
-		return 1;
-	}
-	switch_chip_id_adjuest();
-	#endif
-#else
-#ifdef BOARD_AR71XX
-	struct ag71xx_mdio *am;
-#endif
-	struct device *miidev;
-	char busid[MII_BUS_ID_SIZE];
-	snprintf(busid, MII_BUS_ID_SIZE, "%s.%d",
-		IPQ806X_MDIO_BUS_NAME, IPQ806X_MDIO_BUS_NUM);
-
-	miidev = bus_find_device_by_name(&platform_bus_type, NULL, busid);
-	if (!miidev) {
-		printk("cannot get mii bus\n");
-		return 1;
-	}
-
-#ifdef BOARD_AR71XX
-	am = dev_get_drvdata(miidev);
-	miibus = am->mii_bus;
-#else
-	miibus = dev_get_drvdata(miidev);
-#endif
-
-#ifdef BOARD_AR71XX
-	if(switch_chip_id_adjuest()) {
-
-		snprintf(busid, MII_BUS_ID_SIZE, "%s.%d",
-		IPQ806X_MDIO_BUS_NAME, MDIO_BUS_1);
-
-		miidev = bus_find_device_by_name(&platform_bus_type, NULL, busid);
-		if (!miidev) {
-			printk("cannot get mii bus\n");
-			return 1;
-		}
-
-		am = dev_get_drvdata(miidev);
-		miibus = am->mii_bus;
-		printk("chip_version:0x%x\n", (qca_ar8216_mii_read(0)&0xff00)>>8);
-	}
-#endif
-
-	if(!miidev){
-		printk("mdio bus '%s' get FAIL\n", busid);
-		return 1;
-	}
-#endif
-
-	return 0;
-}
-
-
 static int ssdk_phy_id_get(ssdk_init_cfg *cfg)
 {
 	a_uint32_t phy_id = 0;
@@ -2002,7 +1537,7 @@
 	ess_mac_clock_disable[3] = devm_reset_control_get(&pdev->dev, "ess_mac4_clk_dis");
 	ess_mac_clock_disable[4] = devm_reset_control_get(&pdev->dev, "ess_mac5_clk_dis");
 
-	if (!ess_rst) {
+	if (IS_ERR(ess_rst)) {
 		printk("ess rst fail!\n");
 		return -1;
 	}
@@ -2277,8 +1812,8 @@
 		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));
+			value = readl(qca_phy_priv_global->hw_addr + 0x66c + phy * 0xc);
+			writel((value|(1<<21)), (qca_phy_priv_global->hw_addr + 0x66c + phy * 0xc));
 		}
 
 		for (phy = 0; phy < 5; phy++) {
@@ -2327,137 +1862,17 @@
 	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));
+		value = readl(qca_phy_priv_global->hw_addr+0x66c+phy*0xc);
+		writel((value&(~(1<<21))), (qca_phy_priv_global->hw_addr+0x66c+phy*0xc));
 		/*diable phy mdio broadcast write*/
 		qca_phy_mmd_write(0, phy, 7, 0x8028, 0x001f);
 	}
 
 	/* clear fdb entry */
-	fal_fdb_del_all(0,1);
+	fal_fdb_entry_flush(0,1);
 }
 #endif
 
-int
-ssdk_plat_init(ssdk_init_cfg *cfg)
-{
-	#ifdef BOARD_AR71XX
-	int rv = 0;
-	#endif
-	printk("ssdk_plat_init start\n");
-	mutex_init(&switch_mdio_lock);
-
-	if(miibus_get())
-		return -ENODEV;
-
-	#ifdef DESS
-	if(ssdk_dt_global.switch_reg_access_mode == HSL_REG_LOCAL_BUS) {
-		/* Enable ess clock here */
-		if(!IS_ERR(ssdk_dt_global.ess_clk))
-		{
-			printk("enable ess clk\n");
-			clk_prepare_enable(ssdk_dt_global.ess_clk);
-		}
-
-		if (!request_mem_region(ssdk_dt_global.switchreg_base_addr,
-				ssdk_dt_global.switchreg_size, "switch_mem")) {
-			printk("%s Unable to request resource.", __func__);
-			return -1;
-		}
-
-		hw_addr = ioremap_nocache(ssdk_dt_global.switchreg_base_addr,
-				ssdk_dt_global.switchreg_size);
-		if (!hw_addr) {
-			printk("%s ioremap fail.", __func__);
-			return -1;
-		}
-		cfg->reg_mode = HSL_HEADER;
-#ifndef BOARD_AR71XX
-#if defined(CONFIG_OF) && (LINUX_VERSION_CODE >= KERNEL_VERSION(3,14,0))
-		platform_driver_register(&ssdk_driver);
-#endif
-#endif
-	}
-
-	if(ssdk_dt_global.psgmii_reg_access_mode == HSL_REG_LOCAL_BUS) {
-		if (!request_mem_region(ssdk_dt_global.psgmiireg_base_addr,
-				ssdk_dt_global.psgmiireg_size, "psgmii_mem")) {
-			printk("%s Unable to request psgmii resource.", __func__);
-			return -1;
-		}
-
-		psgmii_hw_addr = ioremap_nocache(ssdk_dt_global.psgmiireg_base_addr,
-				ssdk_dt_global.psgmiireg_size);
-		if (!psgmii_hw_addr) {
-			printk("%s ioremap fail.", __func__);
-			cfg->reg_func.psgmii_reg_set = NULL;
-			cfg->reg_func.psgmii_reg_get = NULL;
-			return -1;
-		}
-
-		cfg->reg_func.psgmii_reg_set = qca_psgmii_reg_write;
-		cfg->reg_func.psgmii_reg_get = qca_psgmii_reg_read;
-	}
-	#endif
-
-	if(ssdk_dt_global.switch_reg_access_mode == HSL_REG_MDIO) {
-		if(driver_find(qca_phy_driver.name, &mdio_bus_type)){
-			printk("QCA PHY driver had been Registered\n");
-			return 0;
-		}
-		cfg->reg_mode = HSL_MDIO;
-
-		printk("Register QCA PHY driver\n");
-#ifndef BOARD_AR71XX
-		return phy_driver_register(&qca_phy_driver);
-#else
-		rv = phy_driver_register(&qca_phy_driver);
-		ssdk_uci_takeover_init();
-#if (LINUX_VERSION_CODE < KERNEL_VERSION(4,4,0))
-#ifdef CONFIG_AR8216_PHY
-		ar8327_port_link_notify_register(ssdk_port_link_notify);
-#endif
-		ar7240_port_link_notify_register(ssdk_port_link_notify);
-#endif
-		return rv;
-
-#endif
-	} else
-		return 0;
-
-}
-
-void
-ssdk_plat_exit(void)
-{
-    printk("ssdk_plat_exit\n");
-
-	if(ssdk_dt_global.switch_reg_access_mode == HSL_REG_MDIO) {
-#ifndef BOARD_AR71XX
-		phy_driver_unregister(&qca_phy_driver);
-#endif
-
-	#ifdef BOARD_AR71XX
-		ssdk_uci_takeover_exit();
-	#endif
-	}
-
-	if (ssdk_dt_global.switch_reg_access_mode == HSL_REG_LOCAL_BUS) {
-		iounmap(hw_addr);
-		iounmap(psgmii_hw_addr);
-		release_mem_region(ssdk_dt_global.switchreg_base_addr,
-					ssdk_dt_global.switchreg_size);
-		release_mem_region(ssdk_dt_global.psgmiireg_base_addr,
-					ssdk_dt_global.psgmiireg_size);
-#ifndef BOARD_AR71XX
-#if defined(CONFIG_OF) && (LINUX_VERSION_CODE >= KERNEL_VERSION(3,14,0))
-		platform_driver_unregister(&ssdk_driver);
-#endif
-#endif
-	}
-
-}
-
 sw_error_t
 ssdk_init(a_uint32_t dev_id, ssdk_init_cfg * cfg)
 {
@@ -2465,11 +1880,13 @@
 
 	rv = fal_init(dev_id, cfg);
 	if (rv != SW_OK)
-		printk("ssdk fal init failed \r\n");
+		printk("ssdk fal init failed: %d. \r\n", rv);
 
-	ssdk_phy_init(cfg);
-	if (rv != SW_OK)
-		printk("ssdk phy init failed \r\n");
+	if (cfg->chip_type != CHIP_HPPE) {
+		rv = ssdk_phy_init(cfg);
+		if (rv != SW_OK)
+			printk("ssdk phy init failed: %d. \r\n", rv);
+	}
 
 	return rv;
 }
@@ -2515,6 +1932,7 @@
 	struct device_node *switch_node = NULL,*mdio_node = NULL;
 	struct device_node *psgmii_node = NULL;
 	struct device_node *child = NULL;
+	struct device_node *uniphy_node = NULL;
 	a_uint32_t len = 0,i = 0,j = 0;
 	const __be32 *reg_cfg, *mac_mode,*led_source,*phy_addr;
 	const __be32 *led_number;
@@ -2559,6 +1977,53 @@
 	else
 		ssdk_dt_global.switch_reg_access_mode = HSL_REG_MDIO;
 
+	mac_mode = of_get_property(switch_node, "switch_mac_mode", &len);
+	if (!mac_mode)
+		printk("%s: error reading device node properties for mac mode\n", switch_node->name);
+	else {
+		cfg->mac_mode = be32_to_cpup(mac_mode);
+		printk("mac mode = %d\n", be32_to_cpup(mac_mode));
+		ssdk_dt_global.mac_mode = cfg->mac_mode;
+	}
+
+	mac_mode = of_get_property(switch_node, "switch_mac_mode1", &len);
+	if(!mac_mode)
+		printk("%s: error reading device node properties for mac mode1\n", switch_node->name);
+	else {
+		cfg->mac_mode1 = be32_to_cpup(mac_mode);
+		printk("mac mode1 = %d\n", be32_to_cpup(mac_mode));
+		ssdk_dt_global.mac_mode1 = cfg->mac_mode1;
+	}
+
+	mac_mode = of_get_property(switch_node, "switch_mac_mode2", &len);
+	if(!mac_mode)
+		printk("%s: error reading device node properties for mac mode2\n", switch_node->name);
+	else {
+		cfg->mac_mode2 = be32_to_cpup(mac_mode);
+		printk("mac mode2 = %d\n", be32_to_cpup(mac_mode));
+		ssdk_dt_global.mac_mode2 = cfg->mac_mode2;
+	}
+
+	// read uniphy register base and address space
+	uniphy_node = of_find_node_by_name(NULL, "ess-uniphy");
+	if (!uniphy_node)
+		printk("ess-uniphy DT doesn't exist!\n");
+	else {
+		reg_cfg = of_get_property(uniphy_node, "reg", &len);
+		if(!reg_cfg)
+			printk("%s: error reading device node properties for reg\n", uniphy_node->name);
+		else {
+			ssdk_dt_global.uniphyreg_base_addr = be32_to_cpup(reg_cfg);
+			ssdk_dt_global.uniphyreg_size = be32_to_cpup(reg_cfg + 1);
+        	}
+		if (of_property_read_string(uniphy_node, "uniphy_access_mode", (const char **)&ssdk_dt_global.uniphy_access_mode))
+			printk("%s: error reading device node properties for uniphy_access_mode\n", uniphy_node->name);
+		else {
+			if(!strcmp(ssdk_dt_global.uniphy_access_mode, "local bus"))
+				ssdk_dt_global.uniphy_reg_access_mode = HSL_REG_LOCAL_BUS;
+		}
+	}
+
 	if (of_property_read_u32(switch_node, "switch_cpu_bmp", &cfg->port_cfg.cpu_bmp)
 		|| of_property_read_u32(switch_node, "switch_lan_bmp", &cfg->port_cfg.lan_bmp)
 		|| of_property_read_u32(switch_node, "switch_wan_bmp", &cfg->port_cfg.wan_bmp)) {
@@ -2587,15 +2052,6 @@
 	if(!strcmp(ssdk_dt_global.psgmii_reg_access_str, "local bus"))
 		ssdk_dt_global.psgmii_reg_access_mode = HSL_REG_LOCAL_BUS;
 
-	mac_mode = of_get_property(switch_node, "switch_mac_mode", &len);
-	if(!mac_mode) {
-		printk("%s: error reading device node properties for mac mode\n", switch_node->name);
-		return SW_BAD_PARAM;
-	}
-	cfg->mac_mode = be32_to_cpup(mac_mode);
-	printk("mac mode=%d\n", be32_to_cpup(mac_mode));
-	ssdk_dt_global.mac_mode = cfg->mac_mode;
-	printk("current mac mode = %d\n", ssdk_dt_global.mac_mode);
 	for_each_available_child_of_node(switch_node, child) {
 
 		led_source = of_get_property(child, "source", &len);
@@ -2650,7 +2106,7 @@
 
 		phy_addr = of_get_property(child, "reg", &len);
 		if (phy_addr)
-			phy_address[j] = be32_to_cpup(phy_addr);
+			qca_phy_priv_global->phy_address[j] = be32_to_cpup(phy_addr);
 		j++;
 		if (j >= 5)
 			break;
@@ -2660,6 +2116,61 @@
 #endif
 #endif
 
+static void ssdk_driver_register(void)
+{
+#ifdef DESS
+	if(ssdk_dt_global.switch_reg_access_mode == HSL_REG_LOCAL_BUS) {
+#ifndef BOARD_AR71XX
+#if defined(CONFIG_OF) && (LINUX_VERSION_CODE >= KERNEL_VERSION(3,14,0))
+		platform_driver_register(&ssdk_driver);
+#endif
+#endif
+	}
+#endif
+
+	if(ssdk_dt_global.switch_reg_access_mode == HSL_REG_MDIO) {
+		if(driver_find(qca_phy_driver.name, &mdio_bus_type)){
+			printk("QCA PHY driver had been Registered\n");
+			return;
+		}
+
+		printk("Register QCA PHY driver\n");
+#ifndef BOARD_AR71XX
+		phy_driver_register(&qca_phy_driver);
+#else
+		phy_driver_register(&qca_phy_driver);
+		ssdk_uci_takeover_init();
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(4,4,0))
+#ifdef CONFIG_AR8216_PHY
+		ar8327_port_link_notify_register(ssdk_port_link_notify);
+#endif
+		ar7240_port_link_notify_register(ssdk_port_link_notify);
+#endif		
+#endif
+	}
+}
+
+static void ssdk_driver_unregister(void)
+{
+	if(ssdk_dt_global.switch_reg_access_mode == HSL_REG_MDIO) {
+#ifndef BOARD_AR71XX
+		phy_driver_unregister(&qca_phy_driver);
+#endif
+
+	#ifdef BOARD_AR71XX
+		ssdk_uci_takeover_exit();
+	#endif
+	}
+
+	if (ssdk_dt_global.switch_reg_access_mode == HSL_REG_LOCAL_BUS) {
+#ifndef BOARD_AR71XX
+#if defined(CONFIG_OF) && (LINUX_VERSION_CODE >= KERNEL_VERSION(3,14,0))
+		platform_driver_unregister(&ssdk_driver);
+#endif
+#endif
+	}
+}
+
 static int chip_ver_get(ssdk_init_cfg* cfg)
 {
 	int rv = 0;
@@ -2672,14 +2183,16 @@
 		chip_ver = (reg_val&0xff00)>>8;
 	}
 
-	if(chip_ver == 0x02)
+	if(chip_ver == QCA_VER_AR8227)
 		cfg->chip_type = CHIP_SHIVA;
-	else if(chip_ver == 0x13)
+	else if(chip_ver == QCA_VER_AR8337)
 		cfg->chip_type = CHIP_ISISC;
-	else if(chip_ver == 0x12)
+	else if(chip_ver == QCA_VER_AR8327)
 		cfg->chip_type = CHIP_ISIS;
-	else if(chip_ver == 0x14)
+	else if(chip_ver == QCA_VER_DESS)
 		cfg->chip_type = CHIP_DESS;
+	else if(chip_ver == QCA_VER_HPPE)
+		cfg->chip_type = CHIP_HPPE;
 	else
 		rv = -ENODEV;
 
@@ -3064,6 +2577,942 @@
 }
 #endif
 
+#ifdef HPPE
+static int qca_hppe_vsi_hw_init(void)
+{
+	return ppe_vsi_init(0);
+#if 0
+#ifdef ESS_ONLY_FPGA
+	a_uint32_t port_default_vsi[6] = {2, 2, 2, 2, 3, 3};
+#else
+	a_uint32_t port_default_vsi[6] = {0, 1, 2, 3, 4, 5};
+#endif
+	a_uint32_t port_id = 0;
+
+	fal_vsi_newaddr_lrn_t newaddr_lrn = {0};
+	fal_vsi_stamove_t stamove = {0};
+	fal_vsi_member_t member = {0};
+	newaddr_lrn.action = 0;
+	newaddr_lrn.lrn_en = 1;
+	stamove.action = 0;
+	stamove.stamove_en = 1;
+
+	for(port_id = 1; port_id <= 6; port_id++)/*clean vsi table as zero*/
+		fal_vsi_member_set(0, port_default_vsi[port_id-1], &member);
+
+	for(port_id = 1; port_id <= 6; port_id++)
+	{
+		fal_vsi_newaddr_lrn_set(0, port_default_vsi[port_id-1], &newaddr_lrn);
+		fal_vsi_stamove_set(0, port_default_vsi[port_id-1], &stamove);
+		fal_port_vsi_set(0, port_id, port_default_vsi[port_id-1]);
+		fal_vsi_member_get(0, port_default_vsi[port_id-1], &member);
+		member.member_ports |= ((1<<port_id)|0x1);
+		member.bc_ports |= ((1<<port_id)|0x1);
+		member.umc_ports |= ((1<<port_id)|0x1);
+		member.uuc_ports |= ((1<<port_id)|0x1);
+		fal_vsi_member_set(0, port_default_vsi[port_id-1], &member);
+	}
+
+	return 0;
+#endif
+}
+
+static int qca_hppe_fdb_hw_init(void)
+{
+	union port_bridge_ctrl_u value = {0};
+	a_uint32_t port = 0;
+
+	for(port = 0; port < 7; port++)
+	{
+		value.bf.new_addr_lrn_en = 1;
+		value.bf.new_addr_fwd_cmd = 0;
+		value.bf.station_move_lrn_en = 1;
+		value.bf.station_move_fwd_cmd = 0;
+		value.bf.port_isolation_bitmap = 0x7f;
+		value.bf.txmac_en = 1;
+		value.bf.promisc_en = 1;
+
+		hppe_port_bridge_ctrl_set(0, port, &value);
+	}
+
+	value.bf.txmac_en = 0;
+	//hppe_port_bridge_ctrl_set(0, 0, &value);
+	hppe_port_bridge_ctrl_set(0, 7, &value);
+
+	hppe_l2_global_conf_age_en_set(0, 1);
+	hppe_l2_global_conf_lrn_en_set(0, 1);
+
+	return 0;
+}
+
+static int
+qca_hppe_portctrl_hw_init(void)
+{
+	a_uint32_t i = 0, val;
+	a_uint32_t addr_delta = 0x200;
+
+	for(i = 0; i < 6; i++) {
+		val = 0x73;
+		qca_switch_reg_write(0, 0x001000 + (addr_delta*i), (a_uint8_t *)&val, 4);
+		val = 0x2;
+		qca_switch_reg_write(0, 0x001004 + (addr_delta*i), (a_uint8_t *)&val, 4);
+		val = 0x1;
+		qca_switch_reg_write(0, 0x001034 + (addr_delta*i), (a_uint8_t *)&val, 4);
+	}
+
+	return 0;
+}
+
+static int
+qca_hppe_policer_hw_init(void)
+{
+	a_uint32_t i = 0;
+
+	fal_policer_timeslot_set(0, 600);
+
+	for(i = 0; i < 8; i ++)
+	{
+		fal_port_policer_compensation_byte_set(0, i, 4);
+	}
+
+	return 0;
+}
+
+static int
+qca_hppe_shaper_hw_init(void)
+{
+	fal_shaper_token_number_t port_token_number, queue_token_number;
+	fal_shaper_token_number_t flow_token_number;
+	a_uint32_t i = 0;
+
+	port_token_number.c_token_number_negative_en = 0;
+	port_token_number.c_token_number = 0x3fffffff;
+	queue_token_number.c_token_number_negative_en = 0;
+	queue_token_number.c_token_number = 0x3fffffff;
+	queue_token_number.e_token_number_negative_en = 0;
+	queue_token_number.e_token_number = 0x3fffffff;
+	flow_token_number.c_token_number_negative_en = 0;
+	flow_token_number.c_token_number = 0x3fffffff;
+	flow_token_number.e_token_number_negative_en = 0;
+	flow_token_number.e_token_number = 0x3fffffff;
+
+	for(i = 0; i < 8; i ++)
+	{
+		fal_port_shaper_token_number_set(0, i, &port_token_number);
+	}
+
+	for(i = 0; i < 300; i ++)
+	{
+		fal_queue_shaper_token_number_set(0, i, &queue_token_number);
+	}
+
+	for(i = 0; i < 64; i ++)
+	{
+		fal_flow_shaper_token_number_set(0, i, &flow_token_number);
+	}
+
+	fal_port_shaper_timeslot_set(0, 8);
+	fal_flow_shaper_timeslot_set(0, 64);
+	fal_queue_shaper_timeslot_set(0, 300);
+	fal_shaper_ipg_preamble_length_set(0, 20);
+
+	return 0;
+}
+
+static int
+qca_hppe_portvlan_hw_init(void)
+{
+	a_uint32_t port_id = 0, vsi_idx = 0;
+	fal_global_qinq_mode_t global_qinq_mode;
+	fal_port_qinq_role_t port_qinq_role;
+	fal_tpid_t in_eg_tpid;
+	fal_vlantag_egress_mode_t vlantag_eg_mode;
+
+	/* configure ingress/egress global QinQ mode as ctag/ctag */
+	global_qinq_mode.mask = 0x3;
+	global_qinq_mode.ingress_mode = FAL_QINQ_CTAG_MODE;
+	global_qinq_mode.egress_mode = FAL_QINQ_CTAG_MODE;
+	fal_global_qinq_mode_set(0, &global_qinq_mode);
+
+	/* configure port0 - port7 ingress/egress QinQ role as edge/edge */
+	port_qinq_role.mask = 0x3;
+	port_qinq_role.ingress_port_role = FAL_QINQ_CORE_PORT;
+	port_qinq_role.egress_port_role = FAL_QINQ_CORE_PORT;
+	fal_port_qinq_mode_set(0, 0, &port_qinq_role);
+	port_qinq_role.mask = 0x3;
+	port_qinq_role.ingress_port_role = FAL_QINQ_EDGE_PORT;
+	port_qinq_role.egress_port_role = FAL_QINQ_EDGE_PORT;
+	for (port_id = 1; port_id < 8; port_id++)
+		fal_port_qinq_mode_set(0, port_id, &port_qinq_role);
+
+	/* configure ingress and egress stpid/ctpid as 0x88a8/0x8100 */
+	in_eg_tpid.mask = 0x3;
+	in_eg_tpid.ctpid = FAL_DEF_VLAN_CTPID;
+	in_eg_tpid.stpid = FAL_DEF_VLAN_STPID;
+	fal_ingress_tpid_set(0, &in_eg_tpid);
+	fal_egress_tpid_set(0, &in_eg_tpid);
+
+	/* configure port0 - port7 ingress vlan translation mismatched command as forward*/
+	for (port_id = 0; port_id < 8; port_id++)
+		fal_port_vlan_xlt_miss_cmd_set(0, port_id, FAL_MAC_FRWRD);
+
+	/* configure port0 - port7 stag/ctag egress mode as unmodified/unmodified */
+	vlantag_eg_mode.mask = 0x3;
+	vlantag_eg_mode.stag_mode = FAL_EG_UNMODIFIED;
+	vlantag_eg_mode.ctag_mode = FAL_EG_UNMODIFIED;
+	for (port_id = 0; port_id < 8; port_id++)
+		fal_port_vlantag_egmode_set(0, port_id, &vlantag_eg_mode);
+
+	/* configure the port0 - port7 of vsi0 - vsi31 to unmodified */
+	for (vsi_idx = 0; vsi_idx < 32; vsi_idx++)
+		for (port_id = 0; port_id < 8; port_id++)
+			fal_port_vsi_egmode_set(0, vsi_idx, port_id, FAL_EG_UNMODIFIED);
+
+	/* configure port0 - port7 vsi tag mode control to enable */
+	for (port_id = 0; port_id < 8; port_id++)
+		fal_port_vlantag_vsi_egmode_enable(0, port_id, A_TRUE);
+
+	return 0;
+}
+
+fal_port_scheduler_cfg_t port_scheduler_tbl[] = {
+	{0xee, 6, 0},
+	{0xde, 4, 5},
+	{0x9f, 0, 6},
+	{0xbe, 5, 0},
+	{0x7e, 6, 7},
+	{0x5f, 0, 5},
+	{0x9f, 7, 6},
+	{0xbe, 5, 0},
+	{0xfc, 6, 1},
+	{0xdd, 0, 5},
+	{0xde, 1, 0},
+	{0xbe, 5, 6},
+	{0xbb, 0, 2},
+	{0xdb, 6, 5},
+	{0xde, 2, 0},
+	{0xbe, 5, 6},
+	{0x3f, 0, 7},
+	{0x7e, 6, 0},
+	{0xde, 7, 5},
+	{0x9f, 0, 6},
+	{0xb7, 5, 3},
+	{0xf6, 6, 0},
+	{0xde, 3, 5},
+	{0x9f, 0, 6},
+	{0xbe, 5, 0},
+	{0xee, 6, 4},
+	{0xcf, 0, 5},
+	{0x9f, 4, 6},
+	{0xbe, 5, 0},
+	{0x7e, 6, 7},
+	{0x5f, 0, 5},
+	{0xde, 7, 0},
+	{0xbe, 5, 6},
+	{0xbd, 0, 1},
+	{0xdd, 6, 5},
+	{0xde, 1, 0},
+	{0xbe, 5, 6},
+	{0xbb, 0, 2},
+	{0xfa, 6, 0},
+	{0xde, 2, 5},
+	{0x9f, 0, 6},
+	{0x3f, 5, 7},
+	{0x7e, 6, 0},
+	{0xde, 7, 5},
+	{0x9f, 0, 6},
+	{0xb7, 5, 3},
+	{0xf6, 6, 0},
+	{0xde, 3, 5},
+	{0x9f, 0, 6},
+	{0xaf, 5, 4},
+};
+
+fal_port_tdm_tick_cfg_t port_tdm_tbl[] = {
+	{1, FAL_PORT_TDB_DIR_INGRESS, 5},
+	{1, FAL_PORT_TDB_DIR_EGRESS, 5},
+	{1, FAL_PORT_TDB_DIR_INGRESS, 0},
+	{1, FAL_PORT_TDB_DIR_EGRESS, 0},
+	{1, FAL_PORT_TDB_DIR_INGRESS, 6},
+	{1, FAL_PORT_TDB_DIR_EGRESS, 6},
+	{1, FAL_PORT_TDB_DIR_INGRESS, 1},
+	{1, FAL_PORT_TDB_DIR_EGRESS, 0},
+	{1, FAL_PORT_TDB_DIR_INGRESS, 7},
+	{1, FAL_PORT_TDB_DIR_EGRESS, 7},
+	{1, FAL_PORT_TDB_DIR_INGRESS, 5},
+	{1, FAL_PORT_TDB_DIR_EGRESS, 5},
+	{1, FAL_PORT_TDB_DIR_INGRESS, 0},
+	{1, FAL_PORT_TDB_DIR_EGRESS, 0},
+	{1, FAL_PORT_TDB_DIR_INGRESS, 6},
+	{1, FAL_PORT_TDB_DIR_EGRESS, 6},
+	{1, FAL_PORT_TDB_DIR_INGRESS, 0},
+	{1, FAL_PORT_TDB_DIR_EGRESS, 3},
+	{1, FAL_PORT_TDB_DIR_INGRESS, 7},
+	{1, FAL_PORT_TDB_DIR_EGRESS, 7},
+	{1, FAL_PORT_TDB_DIR_INGRESS, 5},
+	{1, FAL_PORT_TDB_DIR_EGRESS, 5},
+	{1, FAL_PORT_TDB_DIR_INGRESS, 0},
+	{1, FAL_PORT_TDB_DIR_EGRESS, 0},
+	{1, FAL_PORT_TDB_DIR_INGRESS, 6},
+	{1, FAL_PORT_TDB_DIR_EGRESS, 6},
+	{1, FAL_PORT_TDB_DIR_INGRESS, 0},
+	{1, FAL_PORT_TDB_DIR_EGRESS, 0},
+	{1, FAL_PORT_TDB_DIR_INGRESS, 7},
+	{1, FAL_PORT_TDB_DIR_EGRESS, 7},
+	{1, FAL_PORT_TDB_DIR_INGRESS, 5},
+	{1, FAL_PORT_TDB_DIR_EGRESS, 5},
+	{1, FAL_PORT_TDB_DIR_INGRESS, 0},
+	{1, FAL_PORT_TDB_DIR_EGRESS, 0},
+	{1, FAL_PORT_TDB_DIR_INGRESS, 6},
+	{1, FAL_PORT_TDB_DIR_EGRESS, 6},
+	{1, FAL_PORT_TDB_DIR_INGRESS, 2},
+	{1, FAL_PORT_TDB_DIR_EGRESS, 0},
+	{1, FAL_PORT_TDB_DIR_INGRESS, 7},
+	{1, FAL_PORT_TDB_DIR_EGRESS, 7},
+	{1, FAL_PORT_TDB_DIR_INGRESS, 5},
+	{1, FAL_PORT_TDB_DIR_EGRESS, 5},
+	{1, FAL_PORT_TDB_DIR_INGRESS, 0},
+	{1, FAL_PORT_TDB_DIR_EGRESS, 4},
+	{1, FAL_PORT_TDB_DIR_INGRESS, 6},
+	{1, FAL_PORT_TDB_DIR_EGRESS, 6},
+	{1, FAL_PORT_TDB_DIR_INGRESS, 0},
+	{1, FAL_PORT_TDB_DIR_EGRESS, 0},
+	{1, FAL_PORT_TDB_DIR_INGRESS, 7},
+	{1, FAL_PORT_TDB_DIR_EGRESS, 7},
+	{1, FAL_PORT_TDB_DIR_INGRESS, 5},
+	{1, FAL_PORT_TDB_DIR_EGRESS, 5},
+	{1, FAL_PORT_TDB_DIR_INGRESS, 0},
+	{1, FAL_PORT_TDB_DIR_EGRESS, 0},
+	{1, FAL_PORT_TDB_DIR_INGRESS, 6},
+	{1, FAL_PORT_TDB_DIR_EGRESS, 6},
+	{1, FAL_PORT_TDB_DIR_INGRESS, 0},
+	{1, FAL_PORT_TDB_DIR_EGRESS, 1},
+	{1, FAL_PORT_TDB_DIR_INGRESS, 7},
+	{1, FAL_PORT_TDB_DIR_EGRESS, 7},
+	{1, FAL_PORT_TDB_DIR_INGRESS, 5},
+	{1, FAL_PORT_TDB_DIR_EGRESS, 5},
+	{1, FAL_PORT_TDB_DIR_INGRESS, 0},
+	{1, FAL_PORT_TDB_DIR_EGRESS, 0},
+	{1, FAL_PORT_TDB_DIR_INGRESS, 6},
+	{1, FAL_PORT_TDB_DIR_EGRESS, 6},
+	{1, FAL_PORT_TDB_DIR_INGRESS, 3},
+	{1, FAL_PORT_TDB_DIR_EGRESS, 0},
+	{1, FAL_PORT_TDB_DIR_INGRESS, 7},
+	{1, FAL_PORT_TDB_DIR_EGRESS, 7},
+	{1, FAL_PORT_TDB_DIR_INGRESS, 5},
+	{1, FAL_PORT_TDB_DIR_EGRESS, 5},
+	{1, FAL_PORT_TDB_DIR_INGRESS, 0},
+	{1, FAL_PORT_TDB_DIR_EGRESS, 0},
+	{1, FAL_PORT_TDB_DIR_INGRESS, 6},
+	{1, FAL_PORT_TDB_DIR_EGRESS, 6},
+	{1, FAL_PORT_TDB_DIR_INGRESS, 0},
+	{1, FAL_PORT_TDB_DIR_EGRESS, 0},
+	{1, FAL_PORT_TDB_DIR_INGRESS, 7},
+	{1, FAL_PORT_TDB_DIR_EGRESS, 7},
+	{1, FAL_PORT_TDB_DIR_INGRESS, 5},
+	{1, FAL_PORT_TDB_DIR_EGRESS, 5},
+	{1, FAL_PORT_TDB_DIR_INGRESS, 0},
+	{1, FAL_PORT_TDB_DIR_EGRESS, 0},
+	{1, FAL_PORT_TDB_DIR_INGRESS, 6},
+	{1, FAL_PORT_TDB_DIR_EGRESS, 6},
+	{1, FAL_PORT_TDB_DIR_INGRESS, 0},
+	{1, FAL_PORT_TDB_DIR_EGRESS, 2},
+	{1, FAL_PORT_TDB_DIR_INGRESS, 7},
+	{1, FAL_PORT_TDB_DIR_EGRESS, 7},
+	{1, FAL_PORT_TDB_DIR_INGRESS, 5},
+	{1, FAL_PORT_TDB_DIR_EGRESS, 5},
+	{1, FAL_PORT_TDB_DIR_INGRESS, 4},
+	{1, FAL_PORT_TDB_DIR_EGRESS, 0},
+	{1, FAL_PORT_TDB_DIR_INGRESS, 6},
+	{1, FAL_PORT_TDB_DIR_EGRESS, 6},
+	{1, FAL_PORT_TDB_DIR_INGRESS, 0},
+	{1, FAL_PORT_TDB_DIR_EGRESS, 0},
+	{1, FAL_PORT_TDB_DIR_INGRESS, 7},
+	{1, FAL_PORT_TDB_DIR_EGRESS, 7},
+};
+
+static int
+qca_hppe_tdm_hw_init(void)
+{
+	adpt_api_t *p_api;
+	a_uint32_t i = 0;
+	a_uint32_t num = sizeof(port_scheduler_tbl) / sizeof(fal_port_scheduler_cfg_t);
+	fal_port_tdm_ctrl_t tdm_ctrl;
+
+	p_api = adpt_api_ptr_get(0);
+	if (!p_api)
+		return SW_FAIL;
+
+	if (!p_api->adpt_port_scheduler_cfg_set ||
+		!p_api->adpt_tdm_tick_num_set)
+		return SW_FAIL;
+
+	for (i = 0; i < num; i++) {
+		p_api->adpt_port_scheduler_cfg_set(0, i, &port_scheduler_tbl[i]);
+	}
+	p_api->adpt_tdm_tick_num_set(0, num);
+
+	num = sizeof(port_tdm_tbl) / sizeof(fal_port_tdm_tick_cfg_t);
+	for (i = 0; i < num; i++) {
+		p_api->adpt_port_tdm_tick_cfg_set(0, i, &port_tdm_tbl[i]);
+	}
+	tdm_ctrl.enable = 1;
+	tdm_ctrl.offset = 0;
+	tdm_ctrl.depth = 100;
+	p_api->adpt_port_tdm_ctrl_set(0, &tdm_ctrl);
+	printk("tdm setup num=%d\n", num);
+	return 0;
+}
+
+static int
+qca_hppe_xgmac_hw_init(void)
+{
+	a_uint32_t val = 0, i = 0;
+	a_uint32_t xgmac_addr_delta = 0x4000;
+
+	val = 0x15;
+	qca_switch_reg_write(0, 0x00000010, (a_uint8_t *)&val, 4);
+
+	for (i = 0; i < 2; i ++)
+	{
+		val = 0x80010001;
+		qca_switch_reg_write(0, 0x00003000 + (xgmac_addr_delta*i), (a_uint8_t *)&val, 4);
+		val = 0x271c00c7;
+		qca_switch_reg_write(0, 0x00003004 + (xgmac_addr_delta*i), (a_uint8_t *)&val, 4);
+		val = 0x00000001;
+		qca_switch_reg_write(0, 0x00003008 + (xgmac_addr_delta*i), (a_uint8_t *)&val, 4);
+		val = 0x00000001;
+		qca_switch_reg_write(0, 0x00003090 + (xgmac_addr_delta*i), (a_uint8_t *)&val, 4);
+		val = 0x00000002;
+		qca_switch_reg_write(0, 0x00003070 + (xgmac_addr_delta*i), (a_uint8_t *)&val, 4);
+		val = 0x40000;
+		qca_switch_reg_write(0, 0x00003050 + (xgmac_addr_delta*i), (a_uint8_t *)&val, 4);
+	}
+
+	val = 0x0;
+	qca_switch_reg_write(0, 0x00001800, (a_uint8_t *)&val, 4);
+	val = 0x0;
+	qca_switch_reg_write(0, 0x00001a00, (a_uint8_t *)&val, 4);
+
+	return 0;
+}
+
+static int
+qca_hppe_bm_hw_init(void)
+{
+	a_uint32_t i = 0;
+	fal_bm_dynamic_cfg_t cfg;
+
+	for (i = 0; i <  15; i++) {
+		/* enable fc */
+		fal_port_bm_ctrl_set(0, i, 1);
+		/* map to group 0 */
+		fal_port_bufgroup_map_set(0, i, 0);
+	}
+
+	fal_bm_bufgroup_buffer_set(0, 0, 1600);
+
+	/* set reserved buffer */
+	fal_bm_port_reserved_buffer_set(0, 0, 0, 52);
+	for (i = 1; i < 8; i++)
+		fal_bm_port_reserved_buffer_set(0, i, 0, 18);
+	for (i = 8; i < 14; i++)
+		fal_bm_port_reserved_buffer_set(0, i, 0, 163);
+	fal_bm_port_reserved_buffer_set(0, 14, 0, 40);
+
+	memset(&cfg, 0, sizeof(cfg));
+	cfg.resume_min_thresh = 0;
+	cfg.resume_off = 36;
+	cfg.weight= 4;
+	cfg.shared_ceiling = 250;
+	for (i = 0; i < 15; i++)
+		fal_bm_port_dynamic_thresh_set(0, i, &cfg);
+	return 0;
+}
+
+static int
+qca_hppe_qm_hw_init(void)
+{
+	a_uint32_t i, queue_base = 200;
+	fal_ucast_queue_dest_t queue_dst;
+	fal_ac_obj_t obj;
+	fal_ac_ctrl_t ac_ctrl;
+	fal_ac_group_buffer_t group_buff;
+	fal_ac_dynamic_threshold_t  dthresh_cfg;
+	fal_ac_static_threshold_t sthresh_cfg;
+
+	memset(&queue_dst, 0, sizeof(queue_dst));
+	fal_ucast_queue_base_profile_set(0, &queue_dst, 0, 0);
+	/*
+	 * Redirect service code 2 to queue 1
+	 * TODO: keep sync with  NSS
+	 */
+	queue_dst.service_code_en = A_TRUE;
+	queue_dst.service_code = 2;
+	fal_ucast_queue_base_profile_set(0, &queue_dst, 1, 0);
+
+	queue_dst.service_code = 3;
+	fal_ucast_queue_base_profile_set(0, &queue_dst, 128, 0);
+
+	queue_dst.service_code = 4;
+	fal_ucast_queue_base_profile_set(0, &queue_dst, 128, 0);
+
+	queue_dst.service_code = 5;
+	fal_ucast_queue_base_profile_set(0, &queue_dst, 0, 0);
+
+	queue_dst.service_code_en = A_FALSE;
+	queue_dst.service_code = 0;
+	for(i = 1; i < 8; i++) {
+		queue_dst.dst_port = i;
+		fal_ucast_queue_base_profile_set(0, &queue_dst,
+						queue_base + (i-1) * 8, i);
+	}
+
+	/* queue ac*/
+	ac_ctrl.ac_en = 1;
+	ac_ctrl.ac_fc_en = 0;
+	for (i = 0; i < 300; i++) {
+		obj.type = FAL_AC_QUEUE;
+		obj.obj_id = i;
+		fal_ac_ctrl_set(0, &obj, &ac_ctrl);
+		fal_ac_queue_group_set(0, i, 0);
+		fal_ac_prealloc_buffer_set(0, &obj, 0);
+	}
+
+	group_buff.prealloc_buffer = 0;
+	group_buff.total_buffer = 2000;
+	fal_ac_group_buffer_set(0, 0, &group_buff);
+
+	memset(&dthresh_cfg, 0, sizeof(dthresh_cfg));
+	dthresh_cfg.shared_weight = 4;
+	dthresh_cfg.ceiling = 250;
+	dthresh_cfg.green_resume_off = 36;
+	for (i = 0; i < 256; i++)
+		fal_ac_dynamic_threshold_set(0, i, &dthresh_cfg);
+
+	memset(&sthresh_cfg, 0, sizeof(sthresh_cfg));
+	sthresh_cfg.green_max = 250;
+	sthresh_cfg.green_resume_off = 36;
+	for (i = 256; i < 300; i++) {
+		obj.type = FAL_AC_QUEUE;
+		obj.obj_id = i;
+		fal_ac_static_threshold_set(0, &obj, &sthresh_cfg);
+	}
+
+	return 0;
+}
+
+static int
+qca_hppe_qos_scheduler_hw_init(void)
+{
+	a_uint32_t i = 0, j = 0;
+	fal_qos_scheduler_cfg_t cfg;
+	fal_queue_bmp_t queue_bmp;
+	fal_qos_group_t group_sel;
+	fal_qos_pri_precedence_t pri_pre;
+
+	memset(&cfg, 0, sizeof(cfg));
+
+	/* L1 shceduler */
+	for (i = 0; i < 8; i++) {
+		cfg.sp_id = i;
+		cfg.c_pri = 0;
+		cfg.e_pri = 0;
+		cfg.c_drr_id = i;
+		cfg.e_drr_id = i;
+		cfg.c_drr_wt = 1;
+		cfg.e_drr_wt = 1;
+		fal_queue_scheduler_set(0, i, 1, i, &cfg);
+	}
+
+	/* L0 shceduler */
+	/* cpu port unicast queue: 0 ~ 199 */
+	cfg.sp_id = 0;
+	cfg.c_drr_wt = 2;
+	cfg.e_drr_wt = 2;
+	for (i = 0; i < 200; i++) {
+		cfg.c_pri = i % 8;
+		cfg.e_pri = i % 8;
+		cfg.c_drr_id = i % 8;
+		cfg.e_drr_id = i % 8;
+		fal_queue_scheduler_set(0, i, 0, 0, &cfg);
+	}
+	/* cpu port multicast queue: 256 ~ 271 */
+	cfg.c_drr_wt = 1;
+	cfg.e_drr_wt = 1;
+	for (i = 256; i < 272; i++) {
+		cfg.c_pri = i % 8;
+		cfg.e_pri = i % 8;
+		cfg.c_drr_id = i % 8;
+		cfg.e_drr_id = i % 8;
+		fal_queue_scheduler_set(0, i, 0, 0, &cfg);
+	}
+	/* port 1~7 unicast queue: 200 ~ 255  */
+	/* port 1~7 multicast queue: 272 ~ 299  */
+	for (j = 1; j < 8; j++) {
+		cfg.sp_id = j;
+		cfg.c_drr_wt = 2;
+		cfg.e_drr_wt = 2;
+		for (i = 0; i < 8; i++) {
+			cfg.c_pri = i;
+			cfg.e_pri = i;
+			cfg.c_drr_id = i + 8 * j;
+			cfg.e_drr_id = i + 8 * j;
+			fal_queue_scheduler_set(0, 200 + i + (j-1)*8, 0, j, &cfg);
+		}
+
+		cfg.c_drr_wt = 1;
+		cfg.e_drr_wt = 1;
+		for (i = 0; i < 4; i++) {
+			cfg.c_pri = i;
+			cfg.e_pri = i;
+			cfg.c_drr_id = i + 8 * j;
+			cfg.e_drr_id = i + 8 * j;
+			fal_queue_scheduler_set(0,272 + i + (j-1)*4, 0, j, &cfg);
+		}
+	}
+
+	/* queue--edma ring mapping*/
+	memset(&queue_bmp, 0, sizeof(queue_bmp));
+	queue_bmp.bmp[0] = 1;
+	fal_edma_ring_queue_map_set(0, 0, &queue_bmp);
+	queue_bmp.bmp[0] = 2;
+	fal_edma_ring_queue_map_set(0, 1, &queue_bmp);
+	queue_bmp.bmp[0] = 0;
+	queue_bmp.bmp[4] = 0xFFFF;
+	fal_edma_ring_queue_map_set(0, 2, &queue_bmp);
+
+	/* chose qos group 0 */
+	group_sel.dscp_group = 0;
+	group_sel.flow_group = 0;
+	group_sel.pcp_group = 0;
+	for (i = 0; i < 8; i++)
+		fal_qos_port_group_get(0, i, &group_sel);
+	/* qos precedence */
+	pri_pre.flow_pri = 4;
+	pri_pre.acl_pri = 2;
+	pri_pre.dscp_pri = 1;
+	pri_pre.pcp_pri = 0;
+	pri_pre.preheader_pri = 3;
+	for (i = 0; i < 8; i++)
+		fal_qos_port_pri_precedence_set(0, i, &pri_pre);
+
+	return 0;
+}
+
+#ifdef HAWKEYE_CHIP
+static int
+qca_hppe_gcc_uniphy_init(void)
+{
+	gcc_uniphy_base = ioremap_nocache(0x01856000, 0x280);
+	if (!gcc_uniphy_base) {
+		printk("can't get gcc uniphy address!\n");
+		return -1;
+	}
+	printk("Get gcc uniphy address successfully!\n");
+
+	return 0;
+}
+
+static int
+qca_hppe_gcc_speed_clock_init(void)
+{
+	gcc_hppe_clock_config1_base = ioremap_nocache(0x01868020, 0x5c);
+	if (!gcc_hppe_clock_config1_base) {
+		printk("can't get gcc hppe colck config1 address!\n");
+		return -1;
+	}
+	printk("Get gcc hppe colck config1 address successfully!\n");
+
+	gcc_hppe_clock_config2_base = ioremap_nocache(0x01868400, 0x60);
+	if (!gcc_hppe_clock_config2_base) {
+		printk("can't get gcc hppe colck config2 address!\n");
+		return -1;
+	}
+	printk("Get gcc hppe colck config2 address successfully!\n");
+
+	return 0;
+}
+
+uint32_t
+qca_hppe_gcc_speed_clock1_reg_write(a_uint32_t dev_id, a_uint32_t reg_addr,
+				a_uint8_t * reg_data, a_uint32_t len)
+{
+	if (len != sizeof (a_uint32_t))
+        return SW_BAD_LEN;
+
+	if ((reg_addr%4)!= 0)
+	return SW_BAD_PARAM;
+
+	writel(reg_data, gcc_hppe_clock_config1_base + reg_addr);
+
+	return 0;
+}
+
+uint32_t
+qca_hppe_gcc_speed_clock1_reg_read(a_uint32_t dev_id, a_uint32_t reg_addr,
+				a_uint8_t * reg_data, a_uint32_t len)
+{
+	uint32_t reg_val = 0;
+
+	if (len != sizeof (a_uint32_t))
+        return SW_BAD_LEN;
+
+	if ((reg_addr%4)!= 0)
+	return SW_BAD_PARAM;
+
+	reg_val = readl(gcc_hppe_clock_config1_base + reg_addr);
+	aos_mem_copy(reg_data, &reg_val, sizeof (a_uint32_t));
+
+	return 0;
+}
+
+uint32_t
+qca_hppe_gcc_speed_clock2_reg_write(a_uint32_t dev_id, a_uint32_t reg_addr,
+				a_uint8_t * reg_data, a_uint32_t len)
+{
+	if (len != sizeof (a_uint32_t))
+        return SW_BAD_LEN;
+
+	if ((reg_addr%4)!= 0)
+	return SW_BAD_PARAM;
+
+	writel(reg_data, gcc_hppe_clock_config2_base + reg_addr);
+
+	return 0;
+}
+
+uint32_t
+qca_hppe_gcc_speed_clock2_reg_read(a_uint32_t dev_id, a_uint32_t reg_addr,
+				a_uint8_t * reg_data, a_uint32_t len)
+{
+	uint32_t reg_val = 0;
+
+	if (len != sizeof (a_uint32_t))
+        return SW_BAD_LEN;
+
+	if ((reg_addr%4)!= 0)
+	return SW_BAD_PARAM;
+
+	reg_val = readl(gcc_hppe_clock_config2_base + reg_addr);
+	aos_mem_copy(reg_data, &reg_val, sizeof (a_uint32_t));
+
+	return 0;
+}
+
+uint32_t
+qca_hppe_gcc_uniphy_reg_write(a_uint32_t dev_id, a_uint32_t reg_addr, a_uint8_t * reg_data, a_uint32_t len)
+{
+	if (len != sizeof (a_uint32_t))
+        return SW_BAD_LEN;
+
+	if ((reg_addr%4)!= 0)
+	return SW_BAD_PARAM;
+
+	writel(reg_data, gcc_uniphy_base + reg_addr);
+
+	return 0;
+}
+
+uint32_t
+qca_hppe_gcc_uniphy_reg_read(a_uint32_t dev_id, a_uint32_t reg_addr, a_uint8_t * reg_data, a_uint32_t len)
+{
+	uint32_t reg_val = 0;
+
+	if (len != sizeof (a_uint32_t))
+        return SW_BAD_LEN;
+
+	if ((reg_addr%4)!= 0)
+	return SW_BAD_PARAM;
+
+	reg_val = readl(gcc_uniphy_base + reg_addr);
+	aos_mem_copy(reg_data, &reg_val, sizeof (a_uint32_t));
+
+	return 0;
+}
+static void
+qca_hppe_gcc_uniphy_port_clock_set(a_uint32_t dev_id, a_uint32_t uniphy_index,
+			a_uint32_t port_id, a_bool_t enable)
+{
+	a_uint32_t i, reg_value;
+
+	for (i = 0; i < 2; i++)
+	{
+		reg_value = 0;
+		qca_hppe_gcc_uniphy_reg_read(0, (((0x10 + i * 4) + 0x8 * (port_id - 1))
+				+ (uniphy_index * HPPE_GCC_UNIPHY_REG_INC)), (a_uint8_t *)&reg_value, 4);
+		if (enable == A_TRUE)
+			reg_value |= 0x1;
+		else
+			reg_value &= ~0x1;
+		qca_hppe_gcc_uniphy_reg_write(0, (((0x10 + i * 4)+ 0x8 * (port_id - 1))
+				+ (uniphy_index * HPPE_GCC_UNIPHY_REG_INC)), (a_uint8_t *)&reg_value, 4);
+	}
+
+}
+
+sw_error_t
+qca_hppe_xgphy_read(a_uint32_t dev_id, a_uint32_t phy_addr,
+                           a_uint32_t reg, a_uint16_t* data)
+{
+	struct mii_bus *bus = miibus;
+	int phy_dest_addr;
+
+	phy_dest_addr = phy_address[phy_addr];
+	reg = MII_PHYADDR_C45 | reg;
+	*data = mdiobus_read(bus, phy_dest_addr, reg);
+
+	return 0;
+}
+sw_error_t
+qca_hppe_xgphy_write(a_uint32_t dev_id, a_uint32_t phy_addr,
+                            a_uint32_t reg, a_uint16_t data)
+{
+	struct mii_bus *bus = miibus;
+	int phy_dest_addr;
+
+	phy_dest_addr = phy_address[phy_addr];
+	reg = MII_PHYADDR_C45 | reg;
+	mdiobus_write(bus, phy_dest_addr, reg, data);
+
+	return 0;
+}
+#endif
+
+uint32_t
+qca_hppe_uniphy_reg_read(a_uint32_t dev_id, a_uint32_t uniphy_index,
+				a_uint32_t reg_addr, a_uint8_t * reg_data, a_uint32_t len)
+{
+	uint32_t reg_val = 0;
+	void __iomem *hppe_uniphy_base = NULL;
+	a_uint32_t reg_addr1, reg_addr2;
+
+	if (len != sizeof (a_uint32_t))
+        return SW_BAD_LEN;
+
+	if ((reg_addr%4)!= 0)
+	return SW_BAD_PARAM;
+
+	if (HPPE_UNIPHY_INSTANCE0 == uniphy_index)
+		hppe_uniphy_base = hppe_uniphy_addr;
+	else if (HPPE_UNIPHY_INSTANCE1 == uniphy_index)
+		hppe_uniphy_base = hppe_uniphy_addr + HPPE_UNIPHY_BASE1;
+
+	else if (HPPE_UNIPHY_INSTANCE2 == uniphy_index)
+		hppe_uniphy_base = hppe_uniphy_addr + HPPE_UNIPHY_BASE2;
+
+	if ( reg_addr > HPPE_UNIPHY_MAX_DIRECT_ACCESS_REG)
+	{
+		// uniphy reg indireclty access
+		reg_addr1 = reg_addr & HPPE_UNIPHY_INDIRECT_HIGH_ADDR;
+		writel(reg_addr1, hppe_uniphy_base + HPPE_UNIPHY_INDIRECT_REG_ADDR);
+
+		reg_addr2 = reg_addr & HPPE_UNIPHY_INDIRECT_LOW_ADDR;
+		reg_addr = (HPPE_UNIPHY_INDIRECT_DATA << 10) | (reg_addr2 << 2);
+
+		reg_val = readl(hppe_uniphy_base + reg_addr);
+		aos_mem_copy(reg_data, &reg_val, sizeof (a_uint32_t));
+	}
+	else
+	{	// uniphy reg directly access
+		reg_val = readl(hppe_uniphy_base + reg_addr);
+		aos_mem_copy(reg_data, &reg_val, sizeof (a_uint32_t));
+	}
+
+	return 0;
+}
+
+uint32_t
+qca_hppe_uniphy_reg_write(a_uint32_t dev_id, a_uint32_t uniphy_index,
+				a_uint32_t reg_addr, a_uint8_t * reg_data, a_uint32_t len)
+{
+	void __iomem *hppe_uniphy_base = NULL;
+	a_uint32_t reg_addr1, reg_addr2;
+
+	if (len != sizeof (a_uint32_t))
+        return SW_BAD_LEN;
+
+	if ((reg_addr%4)!= 0)
+	return SW_BAD_PARAM;
+
+	if (HPPE_UNIPHY_INSTANCE0 == uniphy_index)
+		hppe_uniphy_base = hppe_uniphy_addr;
+	else if (HPPE_UNIPHY_INSTANCE1 == uniphy_index)
+		hppe_uniphy_base = hppe_uniphy_addr + HPPE_UNIPHY_BASE1;
+
+	else if (HPPE_UNIPHY_INSTANCE2 == uniphy_index)
+		hppe_uniphy_base = hppe_uniphy_addr + HPPE_UNIPHY_BASE2;
+
+	if ( reg_addr > HPPE_UNIPHY_MAX_DIRECT_ACCESS_REG)
+	{
+		// uniphy reg indireclty access
+		reg_addr1 = reg_addr & HPPE_UNIPHY_INDIRECT_HIGH_ADDR;
+		writel(reg_addr1, hppe_uniphy_base + HPPE_UNIPHY_INDIRECT_REG_ADDR);
+
+		reg_addr2 = reg_addr & HPPE_UNIPHY_INDIRECT_LOW_ADDR;
+		reg_addr = (HPPE_UNIPHY_INDIRECT_DATA << 10) | (reg_addr2 << 2);
+		writel(reg_data, hppe_uniphy_base + reg_addr);
+	}
+	else
+	{	// uniphy reg directly access
+		writel(reg_data, hppe_uniphy_base + reg_addr);
+	}
+
+	return 0;
+}
+
+
+static int
+qca_hppe_hw_init(ssdk_init_cfg *cfg)
+{
+	a_uint32_t val;
+	void __iomem *ppe_gpio_base;
+
+
+	qca_switch_init(0);
+
+	/*fixme*/
+	ppe_gpio_base = ioremap_nocache(0x01008000, 0x100);
+	if (!ppe_gpio_base) {
+		printk("can't get gpio address!\n");
+		return -1;
+	}
+	/* RUMI specific GPIO configuration for enabling XGMAC */
+	writel(0x201, ppe_gpio_base + 0);
+	writel(0x2, ppe_gpio_base + 4);
+	iounmap(ppe_gpio_base);
+	printk("set gpio to enable XGMAC successfully!\n");
+	val = 0x3b;
+	qca_switch_reg_write(0, 0x000010, (a_uint8_t *)&val, 4);
+	val = 0;
+	qca_switch_reg_write(0, 0x000008, (a_uint8_t *)&val, 4);
+
+	qca_hppe_bm_hw_init();
+	qca_hppe_qm_hw_init();
+	qca_hppe_qos_scheduler_hw_init();
+	qca_hppe_tdm_hw_init();
+
+	qca_hppe_fdb_hw_init();
+	qca_hppe_vsi_hw_init();
+	qca_hppe_portvlan_hw_init();
+
+	qca_hppe_portctrl_hw_init();
+
+	qca_hppe_policer_hw_init();
+
+	qca_hppe_shaper_hw_init();
+
+	qca_hppe_xgmac_hw_init();
+	printk("hppe xgmac init success\n");
+#ifdef HAWKEYE_CHIP
+	qca_hppe_gcc_uniphy_init();
+
+	qca_hppe_gcc_speed_clock_init();
+#endif
+	return 0;
+}
+#endif
+
 static void ssdk_cfg_default_init(ssdk_init_cfg *cfg)
 {
 	memset(cfg, 0, sizeof(ssdk_init_cfg));
@@ -3286,7 +3735,7 @@
 static int __init regi_init(void)
 {
 	ssdk_init_cfg cfg;
-	int rv = 0;
+	int rv = 0, cnt = 0;
 	garuda_init_spec_cfg chip_spec_cfg;
 	#ifdef DESS
 	a_uint32_t psgmii_result = 0;
@@ -3294,6 +3743,13 @@
 	ssdk_dt_global.switch_reg_access_mode = HSL_REG_MDIO;
 	ssdk_dt_global.psgmii_reg_access_mode = HSL_REG_MDIO;
 
+	qca_phy_priv_global = kzalloc(sizeof(struct qca_phy_priv), GFP_KERNEL);
+	if (qca_phy_priv_global == NULL) {
+		return -ENOMEM;
+	}
+	for (cnt = 0; cnt < 5; cnt ++)
+		qca_phy_priv_global->phy_address[cnt] = cnt;
+
 	ssdk_cfg_default_init(&cfg);
 
 	#ifndef BOARD_AR71XX
@@ -3306,11 +3762,15 @@
 	if(rv)
 		goto out;
 
+	ssdk_driver_register();
+
 	rv = chip_ver_get(&cfg);
 	if(rv)
 		goto out;
 
-	ssdk_phy_id_get(&cfg);
+	if(cfg.chip_type != CHIP_HPPE)
+		ssdk_phy_id_get(&cfg);
+
 
 	memset(&chip_spec_cfg, 0, sizeof(garuda_init_spec_cfg));
 	cfg.chip_spec_cfg = &chip_spec_cfg;
@@ -3323,8 +3783,14 @@
 	ssdk_dev_notifier.priority = 1;
 	register_netdevice_notifier(&ssdk_dev_notifier);
 
-	#ifdef DESS
+	#if defined(DESS) || defined(HPPE)
 	if(ssdk_dt_global.switch_reg_access_mode == HSL_REG_LOCAL_BUS) {
+		if(cfg.chip_type == CHIP_HPPE)
+		{
+			printk("Initializing HPPE!!\n");
+			qca_hppe_hw_init(&cfg);
+			printk("Initializing HPPE Done!!\n");
+		}
 		/*Do Malibu self test to fix packet drop issue firstly*/
 		if ((cfg.chip_type == CHIP_DESS) && (ssdk_dt_global.mac_mode == PORT_WRAPPER_PSGMII)) {
 			ssdk_psgmii_self_test(A_FALSE, 100, &psgmii_result);
@@ -3366,6 +3832,7 @@
 	#endif
 
 out:
+	fal_module_func_init(0, &cfg);
 	if (rv == 0)
 		printk("qca-ssdk module init succeeded!\n");
 	else {
@@ -3389,6 +3856,8 @@
 	else
 		printk("qca-ssdk module exit failed! (code: %d)\n", rv);
 
+	kfree(qca_phy_priv_global);
+
 	if(ssdk_dt_global.switch_reg_access_mode == HSL_REG_LOCAL_BUS){
 		#ifdef DESS
 		ssdk_switch_unregister();
@@ -3411,6 +3880,8 @@
 	}
 
 	ssdk_plat_exit();
+
+	ssdk_driver_unregister();
 }
 
 module_init(regi_init);
diff --git a/src/init/ssdk_plat.c b/src/init/ssdk_plat.c
new file mode 100755
index 0000000..a71c56c
--- /dev/null
+++ b/src/init/ssdk_plat.c
@@ -0,0 +1,619 @@
+/*
+ * Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ * Permission to use, copy, modify, and/or distribute this software for
+ * any purpose with or without fee is hereby granted, provided that the
+ * above copyright notice and this permission notice appear in all copies.
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
+ * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include "sw.h"
+#include "ssdk_init.h"
+#include "fal_init.h"
+#include "fal.h"
+#include "hsl.h"
+#include "hsl_dev.h"
+#include "ssdk_init.h"
+#include <linux/kconfig.h>
+#include <linux/version.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/phy.h>
+#include <linux/platform_device.h>
+#include <linux/types.h>
+//#include <asm/mach-types.h>
+#include <generated/autoconf.h>
+#include <linux/if_arp.h>
+#include <linux/inetdevice.h>
+#include <linux/netdevice.h>
+#include <linux/phy.h>
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/string.h>
+#if defined(ISIS) ||defined(ISISC) ||defined(GARUDA)
+#include <f1_phy.h>
+#endif
+#if defined(ATHENA) ||defined(SHIVA) ||defined(HORUS)
+#include <f2_phy.h>
+#endif
+#ifdef IN_MALIBU_PHY
+#include <malibu_phy.h>
+#endif
+#if defined(CONFIG_OF) && (LINUX_VERSION_CODE >= KERNEL_VERSION(4,4,0))
+#include <linux/switch.h>
+#include <linux/of.h>
+#elif defined(CONFIG_OF) && (LINUX_VERSION_CODE >= KERNEL_VERSION(3,14,0))
+#include <linux/switch.h>
+#include <linux/of.h>
+#include <drivers/leds/leds-ipq40xx.h>
+#include <linux/of_platform.h>
+#include <linux/reset.h>
+#else
+#include <net/switch.h>
+#include <linux/ar8216_platform.h>
+#include <drivers/net/phy/ar8216.h>
+#include <drivers/net/ethernet/atheros/ag71xx/ag71xx.h>
+#endif
+#include "ssdk_plat.h"
+#include "ref_vlan.h"
+#include "ref_fdb.h"
+#include "ref_mib.h"
+#include "ref_port_ctrl.h"
+#include "ref_misc.h"
+#include "ref_uci.h"
+#include "shell.h"
+#ifdef BOARD_AR71XX
+#include "ssdk_uci.h"
+#endif
+
+#ifdef IN_IP
+#if defined (CONFIG_NF_FLOW_COOKIE)
+#include "fal_flowcookie.h"
+#ifdef IN_SFE
+#include <shortcut-fe/sfe.h>
+#endif
+#endif
+#endif
+
+#ifdef IN_RFS
+#if defined(CONFIG_VLAN_8021Q) || defined(CONFIG_VLAN_8021Q_MODULE)
+#include <linux/if_vlan.h>
+#endif
+#include <qca-rfs/rfs_dev.h>
+#ifdef IN_IP
+#include "fal_rfs.h"
+#endif
+#endif
+
+static struct mii_bus *miibus = NULL;
+
+extern struct qca_phy_priv *qca_phy_priv_global;
+extern ssdk_dt_cfg ssdk_dt_global;
+extern ssdk_chip_type SSDK_CURRENT_CHIP_TYPE;
+extern void __iomem *hppe_uniphy_addr;
+
+static struct mutex switch_mdio_lock;
+
+#ifdef BOARD_IPQ806X
+#define IPQ806X_MDIO_BUS_NAME			"mdio-gpio"
+#endif
+
+#ifdef BOARD_AR71XX
+#define IPQ806X_MDIO_BUS_NAME			"ag71xx-mdio"
+#endif
+#define MDIO_BUS_0						0
+#define MDIO_BUS_1						1
+#define IPQ806X_MDIO_BUS_NUM			MDIO_BUS_0
+
+#define ISIS_CHIP_ID 0x18
+#define ISIS_CHIP_REG 0
+#define SHIVA_CHIP_ID 0x1f
+#define SHIVA_CHIP_REG 0x10
+
+/*
+ * Using ISIS's address as default
+  */
+static int switch_chip_id = ISIS_CHIP_ID;
+static int switch_chip_reg = ISIS_CHIP_REG;
+
+#if defined(CONFIG_OF) && (LINUX_VERSION_CODE >= KERNEL_VERSION(3,14,0))
+struct ag71xx_mdio {
+	struct mii_bus		*mii_bus;
+	int			mii_irq[PHY_MAX_ADDR];
+	void __iomem		*mdio_base;
+};
+#endif
+
+#ifdef BOARD_AR71XX
+static uint32_t switch_chip_id_adjuest(void)
+{
+	uint32_t chip_version = 0;
+	chip_version = (qca_ar8216_mii_read(0)&0xff00)>>8;
+	if((chip_version !=0) && (chip_version !=0xff))
+		return 0;
+
+	switch_chip_id = SHIVA_CHIP_ID;
+	switch_chip_reg = SHIVA_CHIP_REG;
+
+	chip_version = (qca_ar8216_mii_read(0)&0xff00)>>8;
+	printk("chip_version:0x%x\n", chip_version);
+	return 1;
+}
+#endif
+
+static inline void
+split_addr(uint32_t regaddr, uint16_t *r1, uint16_t *r2, uint16_t *page)
+{
+	regaddr >>= 1;
+	*r1 = regaddr & 0x1e;
+
+	regaddr >>= 5;
+	*r2 = regaddr & 0x7;
+
+	regaddr >>= 3;
+	*page = regaddr & 0x3ff;
+}
+
+a_uint32_t
+qca_ar8216_mii_read(a_uint32_t reg)
+{
+        struct mii_bus *bus = miibus;
+        uint16_t r1, r2, page;
+        uint16_t lo, hi;
+
+        split_addr((uint32_t) reg, &r1, &r2, &page);
+        mutex_lock(&switch_mdio_lock);
+        mdiobus_write(bus, switch_chip_id, switch_chip_reg, page);
+	udelay(100);
+        lo = mdiobus_read(bus, 0x10 | r2, r1);
+        hi = mdiobus_read(bus, 0x10 | r2, r1 + 1);
+        mutex_unlock(&switch_mdio_lock);
+        return (hi << 16) | lo;
+}
+
+void
+qca_ar8216_mii_write(a_uint32_t reg, a_uint32_t val)
+{
+        struct mii_bus *bus = miibus;
+        uint16_t r1, r2, r3;
+        uint16_t lo, hi;
+
+        split_addr((a_uint32_t) reg, &r1, &r2, &r3);
+        lo = val & 0xffff;
+        hi = (a_uint16_t) (val >> 16);
+
+        mutex_lock(&switch_mdio_lock);
+        mdiobus_write(bus, switch_chip_id, switch_chip_reg, r3);
+	udelay(100);
+        if(SSDK_CURRENT_CHIP_TYPE != CHIP_SHIVA) {
+            mdiobus_write(bus, 0x10 | r2, r1, lo);
+            mdiobus_write(bus, 0x10 | r2, r1 + 1, hi);
+        } else {
+            mdiobus_write(bus, 0x10 | r2, r1 + 1, hi);
+            mdiobus_write(bus, 0x10 | r2, r1, lo);
+        }
+        mutex_unlock(&switch_mdio_lock);
+}
+
+a_bool_t
+phy_addr_validation_check(a_uint32_t phy_addr)
+{
+
+	if (phy_addr  == SSDK_PHY_BCAST_ID)
+		return A_TRUE;
+	else if ((phy_addr > SSDK_PSGMII_ID) || (phy_addr < SSDK_PHY_MIN_ID))
+		return A_FALSE;
+	else
+		return A_TRUE;
+}
+
+sw_error_t
+qca_ar8327_phy_read(a_uint32_t dev_id, a_uint32_t phy_addr,
+                           a_uint32_t reg, a_uint16_t* data)
+{
+	struct mii_bus *bus = miibus;
+	int phy_dest_addr;
+	if (A_TRUE != phy_addr_validation_check (phy_addr))
+	{
+		return SW_BAD_PARAM;
+	}
+	if (phy_addr == SSDK_PSGMII_ID)
+		phy_dest_addr = qca_phy_priv_global->phy_address[phy_addr -1] + 1;
+	else if (phy_addr == SSDK_PHY_BCAST_ID)
+		phy_dest_addr = SSDK_PHY_BCAST_ID;
+	else
+		phy_dest_addr = qca_phy_priv_global->phy_address[phy_addr];
+
+	*data = mdiobus_read(bus, phy_dest_addr, reg);
+	return 0;
+}
+
+sw_error_t
+qca_ar8327_phy_write(a_uint32_t dev_id, a_uint32_t phy_addr,
+                            a_uint32_t reg, a_uint16_t data)
+{
+	struct mii_bus *bus = miibus;
+	int phy_dest_addr;
+	if (A_TRUE != phy_addr_validation_check (phy_addr))
+	{
+		return SW_BAD_PARAM;
+	}
+	if (phy_addr == SSDK_PSGMII_ID)
+		phy_dest_addr = qca_phy_priv_global->phy_address[phy_addr -1] + 1;
+	else if (phy_addr == SSDK_PHY_BCAST_ID)
+		phy_dest_addr = SSDK_PHY_BCAST_ID;
+	else
+		phy_dest_addr = qca_phy_priv_global->phy_address[phy_addr];
+
+	mdiobus_write(bus, phy_dest_addr, reg, data);
+	return 0;
+}
+
+void
+qca_ar8327_phy_dbg_write(a_uint32_t dev_id, a_uint32_t phy_addr,
+                                a_uint16_t dbg_addr, a_uint16_t dbg_data)
+{
+	struct mii_bus *bus = miibus;
+	int phy_dest_addr;
+	if (A_TRUE != phy_addr_validation_check (phy_addr))
+	{
+		return ;
+	}
+	if (phy_addr == SSDK_PSGMII_ID)
+		phy_dest_addr = qca_phy_priv_global->phy_address[phy_addr -1] + 1;
+	else if (phy_addr == SSDK_PHY_BCAST_ID)
+		phy_dest_addr = SSDK_PHY_BCAST_ID;
+	else
+		phy_dest_addr = qca_phy_priv_global->phy_address[phy_addr];
+
+	mdiobus_write(bus, phy_dest_addr, QCA_MII_DBG_ADDR, dbg_addr);
+	mdiobus_write(bus, phy_dest_addr, QCA_MII_DBG_DATA, dbg_data);
+}
+
+void
+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)
+{
+	struct mii_bus *bus = miibus;
+	int phy_dest_addr;
+	if (A_TRUE != phy_addr_validation_check (phy_addr))
+	{
+		return ;
+	}
+	if (phy_addr == SSDK_PSGMII_ID)
+		phy_dest_addr = qca_phy_priv_global->phy_address[phy_addr -1] + 1;
+	else if (phy_addr == SSDK_PHY_BCAST_ID)
+		phy_dest_addr = SSDK_PHY_BCAST_ID;
+	else
+		phy_dest_addr = qca_phy_priv_global->phy_address[phy_addr];
+
+	mdiobus_write(bus, phy_dest_addr, QCA_MII_DBG_ADDR, dbg_addr);
+	*dbg_data = mdiobus_read(bus, phy_dest_addr, QCA_MII_DBG_DATA);
+}
+
+
+void
+qca_ar8327_mmd_write(a_uint32_t dev_id, a_uint32_t phy_addr,
+                          a_uint16_t addr, a_uint16_t data)
+{
+	struct mii_bus *bus = miibus;
+	int phy_dest_addr;
+	if (A_TRUE != phy_addr_validation_check (phy_addr))
+	{
+		return ;
+	}
+	if (phy_addr == SSDK_PSGMII_ID)
+		phy_dest_addr = qca_phy_priv_global->phy_address[phy_addr -1] + 1;
+	else if (phy_addr == SSDK_PHY_BCAST_ID)
+		phy_dest_addr = SSDK_PHY_BCAST_ID;
+	else
+		phy_dest_addr = qca_phy_priv_global->phy_address[phy_addr];
+
+	mdiobus_write(bus, phy_dest_addr, QCA_MII_MMD_ADDR, addr);
+	mdiobus_write(bus, phy_dest_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;
+}
+
+sw_error_t
+qca_switch_reg_read(a_uint32_t dev_id, a_uint32_t reg_addr, a_uint8_t * reg_data, a_uint32_t len)
+{
+	uint32_t reg_val = 0;
+
+	if (len != sizeof (a_uint32_t))
+        return SW_BAD_LEN;
+
+	if ((reg_addr%4)!= 0)
+	return SW_BAD_PARAM;
+
+	reg_val = readl(qca_phy_priv_global->hw_addr + reg_addr);
+
+	aos_mem_copy(reg_data, &reg_val, sizeof (a_uint32_t));
+	return 0;
+}
+
+sw_error_t
+qca_switch_reg_write(a_uint32_t dev_id, a_uint32_t reg_addr, a_uint8_t * reg_data, a_uint32_t len)
+{
+	uint32_t reg_val = 0;
+	if (len != sizeof (a_uint32_t))
+        return SW_BAD_LEN;
+
+	if ((reg_addr%4)!= 0)
+	return SW_BAD_PARAM;
+
+	aos_mem_copy(&reg_val, reg_data, sizeof (a_uint32_t));
+	writel(reg_val, qca_phy_priv_global->hw_addr + reg_addr);
+	return 0;
+}
+
+sw_error_t
+qca_psgmii_reg_read(a_uint32_t dev_id, a_uint32_t reg_addr, a_uint8_t * reg_data, a_uint32_t len)
+{
+	uint32_t reg_val = 0;
+
+	if (len != sizeof (a_uint32_t))
+        return SW_BAD_LEN;
+
+	if((reg_addr%4)!=0)
+	return SW_BAD_PARAM;
+
+	if (qca_phy_priv_global->psgmii_hw_addr == NULL)
+		return SW_NOT_SUPPORTED;
+
+	reg_val = readl(qca_phy_priv_global->psgmii_hw_addr + reg_addr);
+
+	aos_mem_copy(reg_data, &reg_val, sizeof (a_uint32_t));
+	return 0;
+}
+
+sw_error_t
+qca_psgmii_reg_write(a_uint32_t dev_id, a_uint32_t reg_addr, a_uint8_t * reg_data, a_uint32_t len)
+{
+	uint32_t reg_val = 0;
+	if (len != sizeof (a_uint32_t))
+        return SW_BAD_LEN;
+
+	if((reg_addr%4)!=0)
+	return SW_BAD_PARAM;
+
+	if (qca_phy_priv_global->psgmii_hw_addr == NULL)
+		return SW_NOT_SUPPORTED;
+
+	aos_mem_copy(&reg_val, reg_data, sizeof (a_uint32_t));
+	writel(reg_val, qca_phy_priv_global->psgmii_hw_addr + reg_addr);
+	return 0;
+}
+
+static int miibus_get(void)
+{
+#if defined(CONFIG_OF) && (LINUX_VERSION_CODE >= KERNEL_VERSION(3,14,0))
+	#ifndef BOARD_AR71XX
+	struct device_node *mdio_node = NULL;
+	struct platform_device *mdio_plat = NULL;
+	struct ipq40xx_mdio_data *mdio_data = NULL;
+
+	if(ssdk_dt_global.switch_reg_access_mode == HSL_REG_LOCAL_BUS)
+		mdio_node = of_find_compatible_node(NULL, NULL, "qcom,ipq40xx-mdio");
+	else
+		mdio_node = of_find_compatible_node(NULL, NULL, "virtual,mdio-gpio");
+
+	if (!mdio_node) {
+		printk("No MDIO node found in DTS!\n");
+		return 0;
+	}
+
+	mdio_plat = of_find_device_by_node(mdio_node);
+	if (!mdio_plat) {
+		printk("cannot find platform device from mdio node\n");
+		return 1;
+	}
+
+	if(ssdk_dt_global.switch_reg_access_mode == HSL_REG_LOCAL_BUS)
+	{
+		mdio_data = dev_get_drvdata(&mdio_plat->dev);
+		if (!mdio_data) {
+                	printk("cannot get mdio_data reference from device data\n");
+                	return 1;
+        	}
+		miibus = mdio_data->mii_bus;
+	}
+	else
+		miibus = dev_get_drvdata(&mdio_plat->dev);
+
+	if (!miibus) {
+		printk("cannot get mii bus reference from device data\n");
+		return 1;
+	}
+	#else
+	struct ag71xx_mdio *am;
+	struct device_node *mdio_node = NULL;
+	struct platform_device *mdio_plat = NULL;
+
+	mdio_node = of_find_compatible_node(NULL, NULL, "qca,ag71xx-mdio");
+	if (!mdio_node) {
+		printk("No MDIO node found in DTS!\n");
+		return 1;
+	}
+	mdio_plat = of_find_device_by_node(mdio_node);
+	if (!mdio_plat) {
+		printk("cannot find platform device from mdio node\n");
+		return 1;
+	}
+	am = dev_get_drvdata(&mdio_plat->dev);
+	if (!am) {
+                	printk("cannot get mdio_data reference from device data\n");
+                	return 1;
+	}
+	miibus = am->mii_bus;
+	if (!miibus) {
+		printk("cannot get mii bus reference from device data\n");
+		return 1;
+	}
+	switch_chip_id_adjuest();
+	#endif
+#else
+#ifdef BOARD_AR71XX
+	struct ag71xx_mdio *am;
+#endif
+	struct device *miidev;
+	char busid[MII_BUS_ID_SIZE];
+	snprintf(busid, MII_BUS_ID_SIZE, "%s.%d",
+		IPQ806X_MDIO_BUS_NAME, IPQ806X_MDIO_BUS_NUM);
+
+	miidev = bus_find_device_by_name(&platform_bus_type, NULL, busid);
+	if (!miidev) {
+		printk("cannot get mii bus\n");
+		return 1;
+	}
+
+#ifdef BOARD_AR71XX
+	am = dev_get_drvdata(miidev);
+	miibus = am->mii_bus;
+#else
+	miibus = dev_get_drvdata(miidev);
+#endif
+
+#ifdef BOARD_AR71XX
+	if(switch_chip_id_adjuest()) {
+
+		snprintf(busid, MII_BUS_ID_SIZE, "%s.%d",
+		IPQ806X_MDIO_BUS_NAME, MDIO_BUS_1);
+
+		miidev = bus_find_device_by_name(&platform_bus_type, NULL, busid);
+		if (!miidev) {
+			printk("cannot get mii bus\n");
+			return 1;
+		}
+
+		am = dev_get_drvdata(miidev);
+		miibus = am->mii_bus;
+		printk("chip_version:0x%x\n", (qca_ar8216_mii_read(0)&0xff00)>>8);
+	}
+#endif
+
+	if(!miidev){
+		printk("mdio bus '%s' get FAIL\n", busid);
+		return 1;
+	}
+#endif
+
+	return 0;
+}
+
+int
+ssdk_plat_init(ssdk_init_cfg *cfg)
+{
+	#ifdef BOARD_AR71XX
+	int rv = 0;
+	#endif
+	printk("ssdk_plat_init start\n");
+	mutex_init(&switch_mdio_lock);
+
+	if(miibus_get())
+		return -ENODEV;
+
+
+	#if defined(DESS) || defined(HPPE)
+	if(ssdk_dt_global.switch_reg_access_mode == HSL_REG_LOCAL_BUS) {
+		qca_phy_priv_global->hw_addr = ioremap_nocache(ssdk_dt_global.switchreg_base_addr,
+					ssdk_dt_global.switchreg_size);
+		if (!qca_phy_priv_global->hw_addr) {
+			printk("%s ioremap fail.", __func__);
+			return -1;
+		}
+		if(ssdk_dt_global.uniphy_reg_access_mode == HSL_REG_LOCAL_BUS) {
+			hppe_uniphy_addr = ioremap_nocache(ssdk_dt_global.uniphyreg_base_addr,
+						ssdk_dt_global.uniphyreg_size);
+			if (!hppe_uniphy_addr) {
+				printk("%s ioremap fail.", __func__);
+				return -1;
+			}
+		}
+		if (!ssdk_dt_global.ess_clk || IS_ERR(ssdk_dt_global.ess_clk))
+			return 0;
+		/* Enable ess clock here */
+		printk("enable ess clk\n");
+		clk_prepare_enable(ssdk_dt_global.ess_clk);
+
+		cfg->reg_mode = HSL_HEADER;
+	}
+
+	if(ssdk_dt_global.psgmii_reg_access_mode == HSL_REG_LOCAL_BUS) {
+		if (!request_mem_region(ssdk_dt_global.psgmiireg_base_addr,
+				ssdk_dt_global.psgmiireg_size, "psgmii_mem")) {
+			printk("%s Unable to request psgmii resource.", __func__);
+			return -1;
+		}
+
+		qca_phy_priv_global->psgmii_hw_addr = ioremap_nocache(ssdk_dt_global.psgmiireg_base_addr,
+				ssdk_dt_global.psgmiireg_size);
+		if (!qca_phy_priv_global->psgmii_hw_addr) {
+			printk("%s ioremap fail.", __func__);
+			cfg->reg_func.psgmii_reg_set = NULL;
+			cfg->reg_func.psgmii_reg_get = NULL;
+			return -1;
+		}
+
+		cfg->reg_func.psgmii_reg_set = qca_psgmii_reg_write;
+		cfg->reg_func.psgmii_reg_get = qca_psgmii_reg_read;
+	}
+	#endif
+
+	if(ssdk_dt_global.switch_reg_access_mode == HSL_REG_MDIO) {
+		cfg->reg_mode = HSL_MDIO;
+	} else
+		return 0;
+
+	return 0;
+}
+
+void
+ssdk_plat_exit(void)
+{
+    printk("ssdk_plat_exit\n");
+
+	if (ssdk_dt_global.switch_reg_access_mode == HSL_REG_LOCAL_BUS) {
+		iounmap(qca_phy_priv_global->hw_addr);
+		iounmap(qca_phy_priv_global->psgmii_hw_addr);
+		release_mem_region(ssdk_dt_global.switchreg_base_addr,
+					ssdk_dt_global.switchreg_size);
+		release_mem_region(ssdk_dt_global.psgmiireg_base_addr,
+					ssdk_dt_global.psgmiireg_size);
+	}
+
+}
+