[qca-ssdk] update port interface mode switching solution

Change-Id: I7051c5bfb3dba69359bac3047e484460a8c988ac
Signed-off-by: esong <song@codeaurora.org>
diff --git a/include/hsl/phy/hsl_phy.h b/include/hsl/phy/hsl_phy.h
index 795dc8c..cd25ca7 100755
--- a/include/hsl/phy/hsl_phy.h
+++ b/include/hsl/phy/hsl_phy.h
@@ -626,6 +626,7 @@
 
 sw_error_t
 hsl_ssdk_phy_mode_set(a_uint32_t dev_id, fal_port_interface_mode_t mode);
+phy_type_t hsl_phy_type_get(a_uint32_t dev_id, a_uint32_t port_id);
 /*qca808x_start*/
 sw_error_t ssdk_phy_driver_cleanup(void);
 /*qca808x_end*/
diff --git a/include/hsl/phy/malibu_phy.h b/include/hsl/phy/malibu_phy.h
index fda4c33..397107d 100755
--- a/include/hsl/phy/malibu_phy.h
+++ b/include/hsl/phy/malibu_phy.h
@@ -48,6 +48,7 @@
 #define MALIBU_1_1 0x004DD0B1
 #define MALIBU_1_1_2PORT 0x004DD0B2
 #define MALIBU_ORG_ID_OFFSET_LEN 16
+#define MALIBU_PHY_COPPER_MODE 0x8000
 
   /* PHY Registers */
 #define MALIBU_PHY_CONTROL                      0
diff --git a/src/adpt/hppe/adpt_hppe_portctrl.c b/src/adpt/hppe/adpt_hppe_portctrl.c
index 7ae2690..1dffa25 100755
--- a/src/adpt/hppe/adpt_hppe_portctrl.c
+++ b/src/adpt/hppe/adpt_hppe_portctrl.c
@@ -2245,6 +2245,41 @@
 	}
 	return rv;
 }
+static sw_error_t
+adpt_hppe_port_interface_mode_switch_mac_reset(a_uint32_t dev_id,
+	a_uint32_t port_id)
+{
+	a_uint32_t uniphy_index = 0, mode = 0;
+	sw_error_t rv = 0;
+	phy_type_t phy_type;
+	a_uint32_t port_mac_type;
+
+	phy_type = hsl_phy_type_get(dev_id, port_id);
+	if (phy_type != AQUANTIA_PHY_CHIP) {
+		return SW_OK;
+	}
+
+	if (port_id == HPPE_MUX_PORT1) {
+		uniphy_index = SSDK_UNIPHY_INSTANCE1;
+	} else if (port_id == HPPE_MUX_PORT2) {
+		uniphy_index = SSDK_UNIPHY_INSTANCE2;
+	} else {
+		return SW_OK;
+	}
+
+	mode = ssdk_dt_global_get_mac_mode(dev_id, uniphy_index);
+	if ((mode == PORT_WRAPPER_USXGMII) || (mode == PORT_WRAPPER_SGMII_CHANNEL0)
+			|| (mode == PORT_WRAPPER_SGMII0_RGMII4)) {
+		ssdk_port_mac_clock_reset(dev_id, port_id);
+		port_mac_type = qca_hppe_port_mac_type_get(dev_id, port_id);
+		if (port_mac_type == PORT_XGMAC_TYPE) {
+			/*restore xgmac's pr and pcf setting after reset operation*/
+			rv = adpt_hppe_port_xgmac_promiscuous_mode_set(dev_id,
+			port_id);
+		}
+	}
+	return rv;
+}
 #endif
 sw_error_t
 adpt_hppe_port_mac_speed_set(a_uint32_t dev_id, a_uint32_t port_id,
@@ -2308,7 +2343,24 @@
 			rv = _adpt_cppe_port_mux_mac_set(dev_id, port_id, port_type);
 		}
 	}
-
+#ifdef HAWKEYE_CHIP
+	if (port_id >= HPPE_MUX_PORT1) {
+		if (port_type == PORT_GMAC_TYPE) {
+			rv = _adpt_xgmac_port_txfc_status_set( dev_id, port_id, A_FALSE);
+			SW_RTN_ON_ERROR(rv);
+			rv = _adpt_xgmac_port_rxfc_status_set( dev_id, port_id, A_FALSE);
+			SW_RTN_ON_ERROR(rv);
+		} else if (port_type == PORT_XGMAC_TYPE) {
+			rv = _adpt_gmac_port_txfc_status_set( dev_id, port_id, A_FALSE);
+			SW_RTN_ON_ERROR(rv);
+			rv = _adpt_gmac_port_rxfc_status_set( dev_id, port_id, A_FALSE);
+			SW_RTN_ON_ERROR(rv);
+		} else {
+			return SW_NOT_SUPPORTED;
+		}
+		rv = adpt_hppe_port_interface_mode_switch_mac_reset(dev_id, port_id);
+	}
+#endif
 	return rv;
 }
 
@@ -2742,7 +2794,7 @@
 
 static sw_error_t
 adpt_hppe_port_mac_uniphy_phy_config(a_uint32_t dev_id, a_uint32_t mode_index,
-	a_uint32_t mode[])
+	a_uint32_t mode[], a_bool_t force_switch)
 {
 	sw_error_t rv = SW_OK;
 	a_uint32_t port_id = 0, port_id_from = 0, port_id_end = 0;
@@ -2834,9 +2886,11 @@
 			mode[SSDK_UNIPHY_INSTANCE1]);
 	}
 	SW_RTN_ON_ERROR(rv);
-	rv = _adpt_hppe_port_phy_config(dev_id, mode_index, mode[mode_index]);
-	SSDK_DEBUG("configure phy, mode_index:%x,interface_mode:%x, rv:%x\n",
-		mode_index, mode[mode_index], rv);
+	if (force_switch != A_FALSE) {
+		rv = _adpt_hppe_port_phy_config(dev_id, mode_index, mode[mode_index]);
+		SSDK_DEBUG("configure phy, mode_index:%x,interface_mode:%x, rv:%x\n",
+			mode_index, mode[mode_index], rv);
+	}
 
 	/*init port status for special ports to triger polling*/
 	for(port_id = port_id_from; port_id <= port_id_end; port_id++)
@@ -2848,7 +2902,7 @@
 }
 
 sw_error_t
-_adpt_hppe_port_interface_mode_apply(a_uint32_t dev_id)
+_adpt_hppe_port_interface_mode_apply(a_uint32_t dev_id, a_bool_t force_switch)
 {
 	sw_error_t rv = SW_OK;
 	a_uint32_t mode_index = 0, mode_old[3] = {0};
@@ -2884,7 +2938,8 @@
 		if(mode_new[mode_index] != mode_old[mode_index])
 		{
 			SSDK_DEBUG("need to configure instance%x\n", mode_index);
-			rv = adpt_hppe_port_mac_uniphy_phy_config(dev_id, mode_index, mode_new);
+			rv = adpt_hppe_port_mac_uniphy_phy_config(dev_id,
+				mode_index, mode_new, force_switch);
 			if(rv)
 			{
 				SSDK_ERROR("config instance%x, rv:%x faild\n", mode_index,rv);
@@ -2910,7 +2965,7 @@
 	}
 
 	mutex_lock(&priv->mac_sw_sync_lock);
-	rv = _adpt_hppe_port_interface_mode_apply(dev_id);
+	rv = _adpt_hppe_port_interface_mode_apply(dev_id, A_TRUE);
 	mutex_unlock(&priv->mac_sw_sync_lock);
 	return rv;
 }
@@ -3116,7 +3171,7 @@
 			      fal_port_interface_mode_t * mode)
 {
 
-	sw_error_t rv;
+	sw_error_t rv = SW_OK;
 	a_uint32_t phy_id = 0;
 	hsl_phy_ops_t *phy_drv;
 
@@ -3128,17 +3183,21 @@
 		return SW_BAD_PARAM;
 	  }
 
-	SW_RTN_ON_NULL (phy_drv = hsl_phy_api_ops_get (dev_id, port_id));
-	if (NULL == phy_drv->phy_interface_mode_status_get)
-		return SW_NOT_SUPPORTED;
+	/* for those ports without PHY device should be sfp port */
+	if (A_FALSE == _adpt_hppe_port_phy_connected (dev_id, port_id)) {
+		rv = sfp_phy_interface_get_mode_status(dev_id, port_id, mode);
+		SW_RTN_ON_ERROR (rv);
+	} else {
+		SW_RTN_ON_NULL(phy_drv = hsl_phy_api_ops_get (dev_id, port_id));
+		if (NULL == phy_drv->phy_interface_mode_status_get)
+			return SW_NOT_SUPPORTED;
 
-	rv = hsl_port_prop_get_phyid (dev_id, port_id, &phy_id);
-	SW_RTN_ON_ERROR (rv);
+		rv = hsl_port_prop_get_phyid (dev_id, port_id, &phy_id);
+		SW_RTN_ON_ERROR (rv);
 
-	rv = phy_drv->phy_interface_mode_status_get (dev_id, phy_id,mode);
-
+		rv = phy_drv->phy_interface_mode_status_get (dev_id, phy_id,mode);
+	}
 	return rv;
-
 }
 
 sw_error_t
@@ -4240,13 +4299,12 @@
 	sw_error_t rv = SW_OK;
 	fal_port_interface_mode_t port_mode_old = PORT_INTERFACE_MODE_MAX,
 		port_mode_new= PORT_INTERFACE_MODE_MAX;
-	a_uint32_t phy_addr = 0;
 
 	if (A_FALSE == _adpt_hppe_port_phy_connected(dev_id, port_id))
 	{
 		rv = adpt_hppe_port_interface_mode_get(dev_id, port_id, &port_mode_old);
 		SW_RTN_ON_ERROR(rv);
-		rv = sfp_phy_interface_get_mode_status(dev_id, phy_addr,
+		rv = adpt_hppe_port_interface_mode_status_get(dev_id, port_id,
 			&port_mode_new);
 		SW_RTN_ON_ERROR (rv);
 		if(port_mode_old != port_mode_new)
@@ -4255,7 +4313,7 @@
 				port_mode_new, port_mode_old);
 			rv = adpt_hppe_port_interface_mode_set(dev_id, port_id, port_mode_new);
 			SW_RTN_ON_ERROR(rv);
-			rv = _adpt_hppe_port_interface_mode_apply(dev_id);
+			rv = _adpt_hppe_port_interface_mode_apply(dev_id, A_FALSE);
 			SW_RTN_ON_ERROR(rv);
 		}
 	}
@@ -4264,39 +4322,25 @@
 }
 
 static sw_error_t
-adpt_hppe_mux_port_speed_change_event(a_uint32_t dev_id,
-		a_uint32_t port_id, fal_port_speed_t phy_speed)
+adpt_hppe_port_interface_mode_switch(a_uint32_t dev_id, a_uint32_t port_id)
 {
 	sw_error_t rv = SW_OK;
-	fal_port_interface_mode_t port_mode = PORT_INTERFACE_MODE_MAX;
+	fal_port_interface_mode_t port_mode_old = PORT_INTERFACE_MODE_MAX;
 	fal_port_interface_mode_t port_mode_new = PORT_INTERFACE_MODE_MAX;
-	a_uint32_t port_mac_type = qca_hppe_port_mac_type_get(dev_id, port_id);
 
-	if ((port_id != HPPE_MUX_PORT1 && port_id != HPPE_MUX_PORT2) ||
-			port_mac_type != PORT_GMAC_TYPE) {
-		return SW_NO_CHANGE;
-	}
-
-	rv = adpt_hppe_port_interface_mode_get(dev_id, port_id, &port_mode);
+	rv = adpt_hppe_port_interface_mode_status_get(dev_id,
+		port_id, &port_mode_new);
 	SW_RTN_ON_ERROR(rv);
 
-	if (phy_speed == FAL_SPEED_2500 && port_mode == PHY_SGMII_BASET) {
-		port_mode_new = PORT_SGMII_PLUS;
-	}
-	else if (phy_speed <= FAL_SPEED_1000 && port_mode == PORT_SGMII_PLUS) {
-		port_mode_new = PHY_SGMII_BASET;
-	}
-	else {
-		return SW_NO_CHANGE;
-	}
-
-	rv = adpt_hppe_port_interface_mode_set(dev_id, port_id, port_mode_new);
+	rv = adpt_hppe_port_interface_mode_get(dev_id, port_id, &port_mode_old);
 	SW_RTN_ON_ERROR(rv);
 
-	adpt_hppe_gcc_uniphy_clock_status_set(dev_id, port_id, A_TRUE);
-	rv = _adpt_hppe_port_interface_mode_apply(dev_id);
-	adpt_hppe_gcc_uniphy_clock_status_set(dev_id, port_id, A_FALSE);
-
+	if (port_mode_new != port_mode_old) {
+		rv = adpt_hppe_port_interface_mode_set(dev_id,
+			port_id, port_mode_new);
+		SW_RTN_ON_ERROR(rv);
+		rv = _adpt_hppe_port_interface_mode_apply(dev_id, A_FALSE);
+	}
 	return rv;
 }
 
@@ -4364,6 +4408,12 @@
 			/* disable rx mac */
 			adpt_hppe_port_rxmac_status_set(priv->device_id, port_id, A_FALSE);
 			priv->port_old_link[port_id - 1] = phy_status.link_status;
+			/* switch interface mode if necessary */
+			if (adpt_hppe_port_interface_mode_switch(priv->device_id,
+					port_id) == SW_OK) {
+				SSDK_DEBUG("Port %d the interface mode switched\n",
+						port_id);
+			}
 			continue;
 		}
 		/* link status from down to up*/
@@ -4374,6 +4424,12 @@
 			status = adpt_hppe_port_phy_status_change(priv, port_id, phy_status);
 			/*disable tx mac*/
 			adpt_hppe_port_txmac_status_set(priv->device_id, port_id, A_FALSE);
+			/* switch interface mode if necessary */
+			if (adpt_hppe_port_interface_mode_switch(priv->device_id,
+					port_id) == SW_OK) {
+				SSDK_DEBUG("Port %d the interface mode switched\n",
+						port_id);
+			}
 			if (status == A_TRUE)
 			{
 				adpt_hppe_gcc_uniphy_clock_status_set(priv->device_id,
@@ -4381,13 +4437,6 @@
 				if ((a_uint32_t)phy_status.speed !=
 						priv->port_old_speed[port_id - 1])
 				{
-					/* switch interface mode if necessary */
-					if (adpt_hppe_mux_port_speed_change_event(priv->device_id,
-							port_id, phy_status.speed) == SW_OK) {
-						SSDK_DEBUG("Port %d the interface mode switched\n",
-								port_id);
-					}
-
 					/* configure gcc speed clock according to current speed */
 					adpt_hppe_gcc_port_speed_clock_set(priv->device_id, port_id,
 							phy_status.speed);
diff --git a/src/hsl/phy/hsl_phy.c b/src/hsl/phy/hsl_phy.c
index 353eb0a..7cf825e 100755
--- a/src/hsl/phy/hsl_phy.c
+++ b/src/hsl/phy/hsl_phy.c
@@ -553,6 +553,14 @@
 
 	return SW_OK;
 }
+phy_type_t hsl_phy_type_get(a_uint32_t dev_id, a_uint32_t port_id)
+{
+
+	if (dev_id >= SW_MAX_NR_DEV)
+		return MAX_PHY_CHIP;
+
+	return phy_info[dev_id]->phy_type[port_id];
+}
 /*qca808x_start*/
 sw_error_t ssdk_phy_driver_cleanup(void)
 {
diff --git a/src/hsl/phy/malibu_phy.c b/src/hsl/phy/malibu_phy.c
index 68a7800..3a70e98 100755
--- a/src/hsl/phy/malibu_phy.c
+++ b/src/hsl/phy/malibu_phy.c
@@ -2086,11 +2086,49 @@
 malibu_phy_interface_get_mode(a_uint32_t dev_id, a_uint32_t phy_id, fal_port_interface_mode_t *interface_mode)
 {
 	a_uint16_t phy_data;
-       if (phy_id != COMBO_PHY_ID)
+	a_uint16_t copper_mode;
+
+	if ((phy_id < first_phy_addr) ||
+				(phy_id > (first_phy_addr + MALIBU_PHY_MAX_ADDR_INC))) {
 		return SW_NOT_SUPPORTED;
-	phy_data = malibu_phy_reg_read(dev_id, phy_id, MALIBU_PHY_CHIP_CONFIG);
+	}
+
+	phy_data = malibu_phy_reg_read(dev_id,
+		first_phy_addr + MALIBU_PHY_MAX_ADDR_INC, MALIBU_PHY_CHIP_CONFIG);
+	copper_mode = ((phy_data & MALIBU_PHY_COPPER_MODE) >> 0xf);
 	phy_data &= 0x000f;
-       *interface_mode = phy_data;
+
+	switch (phy_data) {
+		case MALIBU_PHY_PSGMII_BASET:
+			*interface_mode = PHY_PSGMII_BASET;
+			break;
+		case  MALIBU_PHY_PSGMII_BX1000:
+			*interface_mode = PHY_PSGMII_BX1000;
+			break;
+		case MALIBU_PHY_PSGMII_FX100:
+			*interface_mode = PHY_PSGMII_FX100;
+			break;
+		case MALIBU_PHY_PSGMII_AMDET:
+			if (copper_mode) {
+				*interface_mode = PHY_PSGMII_AMDET;
+			 } else {
+				if (phy_id == first_phy_addr + MALIBU_PHY_MAX_ADDR_INC)
+					*interface_mode = PHY_PSGMII_FIBER;
+				else
+					*interface_mode = PHY_PSGMII_AMDET;
+			 }
+			break;
+		case MALIBU_PHY_SGMII_BASET:
+			if (phy_id == first_phy_addr + MALIBU_PHY_MAX_ADDR_INC)
+				*interface_mode = PHY_SGMII_BASET;
+			else
+				*interface_mode = PORT_QSGMII;
+			break;
+		default:
+			*interface_mode = PORT_INTERFACE_MODE_MAX;
+			break;
+	}
+
 	return SW_OK;
 }
 
@@ -2104,12 +2142,50 @@
 malibu_phy_interface_get_mode_status(a_uint32_t dev_id, a_uint32_t phy_id, fal_port_interface_mode_t *interface_mode_status)
 {
 	a_uint16_t phy_data;
-       if (phy_id != COMBO_PHY_ID)
+	a_uint16_t copper_mode;
+
+	if ((phy_id < first_phy_addr) ||
+			       (phy_id > (first_phy_addr + MALIBU_PHY_MAX_ADDR_INC))) {
 		return SW_NOT_SUPPORTED;
-	phy_data = malibu_phy_reg_read(dev_id, phy_id, MALIBU_PHY_CHIP_CONFIG);
+	}
+
+	phy_data = malibu_phy_reg_read(dev_id,
+		first_phy_addr + MALIBU_PHY_MAX_ADDR_INC, MALIBU_PHY_CHIP_CONFIG);
+	copper_mode = ((phy_data & MALIBU_PHY_COPPER_MODE) >> 0xf);
 	phy_data &= 0x00f0;
 	phy_data = (phy_data >>4);
-       *interface_mode_status = phy_data;
+
+	switch (phy_data) {
+		case MALIBU_PHY_PSGMII_BASET:
+			*interface_mode_status = PHY_PSGMII_BASET;
+			break;
+		case  MALIBU_PHY_PSGMII_BX1000:
+			*interface_mode_status = PHY_PSGMII_BX1000;
+			break;
+		case MALIBU_PHY_PSGMII_FX100:
+			*interface_mode_status = PHY_PSGMII_FX100;
+			break;
+		case MALIBU_PHY_PSGMII_AMDET:
+			if (copper_mode) {
+				*interface_mode_status = PHY_PSGMII_BASET;
+			} else {
+				if (phy_id == first_phy_addr + MALIBU_PHY_MAX_ADDR_INC)
+					*interface_mode_status = PHY_PSGMII_FIBER;
+				else
+					*interface_mode_status = PHY_PSGMII_BASET;
+			}
+			break;
+		case MALIBU_PHY_SGMII_BASET:
+			if (phy_id == first_phy_addr + MALIBU_PHY_MAX_ADDR_INC)
+				*interface_mode_status = PHY_SGMII_BASET;
+			else
+				*interface_mode_status = PORT_QSGMII;
+			break;
+		default:
+			*interface_mode_status = PORT_INTERFACE_MODE_MAX;
+			break;
+	}
+
 	return SW_OK;
 }
 
diff --git a/src/hsl/phy/qca803x_phy.c b/src/hsl/phy/qca803x_phy.c
index 9b7a329..34dc50b 100755
--- a/src/hsl/phy/qca803x_phy.c
+++ b/src/hsl/phy/qca803x_phy.c
@@ -1376,6 +1376,7 @@
 			break;
 		default:
 			*interface_mode = PORT_INTERFACE_MODE_MAX;
+			break;
 	}
 
 	return SW_OK;
@@ -1413,6 +1414,7 @@
 			break;
 		default:
 			*interface_mode_status = PORT_INTERFACE_MODE_MAX;
+			break;
 	}
 
 	return SW_OK;
diff --git a/src/hsl/phy/qca808x_phy.c b/src/hsl/phy/qca808x_phy.c
index a1d13fc..c865f69 100755
--- a/src/hsl/phy/qca808x_phy.c
+++ b/src/hsl/phy/qca808x_phy.c
@@ -1467,6 +1467,7 @@
 			break;
 		default:
 			*interface_mode_status = PORT_INTERFACE_MODE_MAX;
+			break;
 	}
 
 	return SW_OK;