powerpc/t4240: add QSGMII interface support

Also some fix for QSGMII.
1. fix QSGMII configure of Serdes2.
2. fix PHY address of QSGMII MAC9 & MAC10 for each FMAN.
3. fix dtb for QSGMII interface.

Signed-off-by: Shaohui Xie <Shaohui.Xie@freescale.com>
Acked-by: York Sun <yorksun@freescale.com>
diff --git a/arch/powerpc/cpu/mpc85xx/t4240_serdes.c b/arch/powerpc/cpu/mpc85xx/t4240_serdes.c
index ed88602..ff55e3c 100644
--- a/arch/powerpc/cpu/mpc85xx/t4240_serdes.c
+++ b/arch/powerpc/cpu/mpc85xx/t4240_serdes.c
@@ -106,25 +106,25 @@
 		SGMII_FM2_DTSEC1, SGMII_FM2_DTSEC2,
 		SGMII_FM2_DTSEC3, SGMII_FM2_DTSEC4}},
 	{38, {NONE, NONE, QSGMII_FM2_B, NONE,
-		NONE, NONE, QSGMII_FM1_A, NONE}},
+		NONE, NONE, QSGMII_FM2_A, NONE} },
 	{40, {SGMII_FM2_DTSEC5, SGMII_FM2_DTSEC6,
 		SGMII_FM2_DTSEC10, SGMII_FM2_DTSEC9,
-		NONE, NONE, QSGMII_FM1_A, NONE}},
+		NONE, NONE, QSGMII_FM2_A, NONE} },
 	{46, {SGMII_FM2_DTSEC5, SGMII_FM2_DTSEC6,
 		SGMII_FM2_DTSEC10, SGMII_FM2_DTSEC9,
-		NONE, NONE, QSGMII_FM1_A, NONE}},
+		NONE, NONE, QSGMII_FM2_A, NONE} },
 	{48, {SGMII_FM2_DTSEC5, SGMII_FM2_DTSEC6,
 		SGMII_FM2_DTSEC10, SGMII_FM2_DTSEC9,
-		NONE, NONE, QSGMII_FM1_A, NONE}},
+		NONE, NONE, QSGMII_FM2_A, NONE} },
 	{50, {XAUI_FM2_MAC9, XAUI_FM2_MAC9,
 		XAUI_FM2_MAC9, XAUI_FM2_MAC9,
-		NONE, NONE, QSGMII_FM1_A, NONE}},
+		NONE, NONE, QSGMII_FM2_A, NONE} },
 	{52, {HIGIG_FM2_MAC9, HIGIG_FM2_MAC9,
 		HIGIG_FM2_MAC9, HIGIG_FM2_MAC9,
-		NONE, NONE, QSGMII_FM1_A, NONE}},
+		NONE, NONE, QSGMII_FM2_A, NONE} },
 	{54, {HIGIG_FM2_MAC9, HIGIG_FM2_MAC9,
 		HIGIG_FM2_MAC9, HIGIG_FM2_MAC9,
-		NONE, NONE, QSGMII_FM1_A, NONE}},
+		NONE, NONE, QSGMII_FM2_A, NONE} },
 	{56, {XFI_FM1_MAC9, XFI_FM1_MAC10,
 		XFI_FM2_MAC10, XFI_FM2_MAC9,
 		SGMII_FM2_DTSEC1, SGMII_FM2_DTSEC2,
diff --git a/board/freescale/t4qds/eth.c b/board/freescale/t4qds/eth.c
index c771e17..b5f488b 100644
--- a/board/freescale/t4qds/eth.c
+++ b/board/freescale/t4qds/eth.c
@@ -172,7 +172,10 @@
 void board_ft_fman_fixup_port(void *blob, char * prop, phys_addr_t pa,
 				enum fm_port port, int offset)
 {
-	if (fm_info_get_enet_if(port) == PHY_INTERFACE_MODE_SGMII) {
+	int interface = fm_info_get_enet_if(port);
+
+	if (interface == PHY_INTERFACE_MODE_SGMII ||
+	    interface == PHY_INTERFACE_MODE_QSGMII) {
 		switch (port) {
 		case FM1_DTSEC1:
 			if (qsgmiiphy_fix[port])
@@ -272,6 +275,7 @@
 	for (i = FM1_DTSEC1; i < NUM_FM_PORTS; i++) {
 		switch (fm_info_get_enet_if(i)) {
 		case PHY_INTERFACE_MODE_SGMII:
+		case PHY_INTERFACE_MODE_QSGMII:
 			switch (mdio_mux[i]) {
 			case EMI1_SLOT1:
 				fdt_status_okay_by_alias(fdt, "emi1_slot1");
@@ -393,7 +397,7 @@
 int board_eth_init(bd_t *bis)
 {
 #if defined(CONFIG_FMAN_ENET)
-	int i, idx, lane, slot;
+	int i, idx, lane, slot, interface;
 	struct memac_mdio_info dtsec_mdio_info;
 	struct memac_mdio_info tgec_mdio_info;
 	ccsr_gur_t *gur = (void *)(CONFIG_SYS_MPC85xx_GUTS_ADDR);
@@ -470,9 +474,9 @@
 		fm_info_set_phy_address(FM1_DTSEC6, slot_qsgmii_phyaddr[1][1]);
 		if ((srds_prtcl_s2 != 56) && (srds_prtcl_s2 != 57)) {
 			fm_info_set_phy_address(FM1_DTSEC9,
-						slot_qsgmii_phyaddr[1][3]);
-			fm_info_set_phy_address(FM1_DTSEC10,
 						slot_qsgmii_phyaddr[1][2]);
+			fm_info_set_phy_address(FM1_DTSEC10,
+						slot_qsgmii_phyaddr[1][3]);
 		}
 		break;
 	case 40:
@@ -482,9 +486,9 @@
 		fm_info_set_phy_address(FM1_DTSEC6, slot_qsgmii_phyaddr[1][1]);
 		if ((srds_prtcl_s2 != 56) && (srds_prtcl_s2 != 57)) {
 			fm_info_set_phy_address(FM1_DTSEC10,
-						slot_qsgmii_phyaddr[1][3]);
-			fm_info_set_phy_address(FM1_DTSEC9,
 						slot_qsgmii_phyaddr[1][2]);
+			fm_info_set_phy_address(FM1_DTSEC9,
+						slot_qsgmii_phyaddr[1][3]);
 		}
 		fm_info_set_phy_address(FM1_DTSEC1, slot_qsgmii_phyaddr[2][0]);
 		fm_info_set_phy_address(FM1_DTSEC2, slot_qsgmii_phyaddr[2][1]);
@@ -498,15 +502,31 @@
 
 	for (i = FM1_DTSEC1; i < FM1_DTSEC1 + CONFIG_SYS_NUM_FM1_DTSEC; i++) {
 		idx = i - FM1_DTSEC1;
-		switch (fm_info_get_enet_if(i)) {
+		interface = fm_info_get_enet_if(i);
+		switch (interface) {
 		case PHY_INTERFACE_MODE_SGMII:
-			lane = serdes_get_first_lane(FSL_SRDS_1,
+		case PHY_INTERFACE_MODE_QSGMII:
+			if (interface == PHY_INTERFACE_MODE_QSGMII) {
+				if (idx <= 3)
+					lane = serdes_get_first_lane(FSL_SRDS_1,
+							QSGMII_FM1_A);
+				else
+					lane = serdes_get_first_lane(FSL_SRDS_1,
+							QSGMII_FM1_B);
+				if (lane < 0)
+					break;
+				slot = lane_to_slot_fsm1[lane];
+				debug("FM1@DTSEC%u expects QSGMII in slot %u\n",
+				      idx + 1, slot);
+			} else {
+				lane = serdes_get_first_lane(FSL_SRDS_1,
 						SGMII_FM1_DTSEC1 + idx);
-			if (lane < 0)
-				break;
-			slot = lane_to_slot_fsm1[lane];
-			debug("FM1@DTSEC%u expects SGMII in slot %u\n",
-				idx + 1, slot);
+				if (lane < 0)
+					break;
+				slot = lane_to_slot_fsm1[lane];
+				debug("FM1@DTSEC%u expects SGMII in slot %u\n",
+				      idx + 1, slot);
+			}
 			if (QIXIS_READ(present2) & (1 << (slot - 1)))
 				fm_disable_port(i);
 			switch (slot) {
@@ -600,8 +620,8 @@
 		fm_info_set_phy_address(FM2_DTSEC4, slot_qsgmii_phyaddr[4][3]);
 		fm_info_set_phy_address(FM2_DTSEC5, slot_qsgmii_phyaddr[3][0]);
 		fm_info_set_phy_address(FM2_DTSEC6, slot_qsgmii_phyaddr[3][1]);
-		fm_info_set_phy_address(FM2_DTSEC9, slot_qsgmii_phyaddr[3][3]);
-		fm_info_set_phy_address(FM2_DTSEC10, slot_qsgmii_phyaddr[3][2]);
+		fm_info_set_phy_address(FM2_DTSEC9, slot_qsgmii_phyaddr[3][2]);
+		fm_info_set_phy_address(FM2_DTSEC10, slot_qsgmii_phyaddr[3][3]);
 		break;
 	case 40:
 	case 46:
@@ -641,15 +661,31 @@
 
 	for (i = FM2_DTSEC1; i < FM2_DTSEC1 + CONFIG_SYS_NUM_FM2_DTSEC; i++) {
 		idx = i - FM2_DTSEC1;
-		switch (fm_info_get_enet_if(i)) {
+		interface = fm_info_get_enet_if(i);
+		switch (interface) {
 		case PHY_INTERFACE_MODE_SGMII:
-			lane = serdes_get_first_lane(FSL_SRDS_2,
+		case PHY_INTERFACE_MODE_QSGMII:
+			if (interface == PHY_INTERFACE_MODE_QSGMII) {
+				if (idx <= 3)
+					lane = serdes_get_first_lane(FSL_SRDS_2,
+							QSGMII_FM2_A);
+				else
+					lane = serdes_get_first_lane(FSL_SRDS_2,
+							QSGMII_FM2_B);
+				if (lane < 0)
+					break;
+				slot = lane_to_slot_fsm2[lane];
+				debug("FM2@DTSEC%u expects QSGMII in slot %u\n",
+				      idx + 1, slot);
+			} else {
+				lane = serdes_get_first_lane(FSL_SRDS_2,
 						SGMII_FM2_DTSEC1 + idx);
-			if (lane < 0)
-				break;
-			slot = lane_to_slot_fsm2[lane];
-			debug("FM2@DTSEC%u expects SGMII in slot %u\n",
-				idx + 1, slot);
+				if (lane < 0)
+					break;
+				slot = lane_to_slot_fsm2[lane];
+				debug("FM2@DTSEC%u expects SGMII in slot %u\n",
+				      idx + 1, slot);
+			}
 			if (QIXIS_READ(present2) & (1 << (slot - 1)))
 				fm_disable_port(i);
 			switch (slot) {
diff --git a/drivers/net/fm/eth.c b/drivers/net/fm/eth.c
index 422c2c6..cb099cd 100644
--- a/drivers/net/fm/eth.c
+++ b/drivers/net/fm/eth.c
@@ -341,7 +341,9 @@
 	mac->init_mac(mac);
 
 	/* For some reason we need to set SPEED_100 */
-	if ((fm_eth->enet_if == PHY_INTERFACE_MODE_SGMII) && mac->set_if_mode)
+	if (((fm_eth->enet_if == PHY_INTERFACE_MODE_SGMII) ||
+	     (fm_eth->enet_if == PHY_INTERFACE_MODE_QSGMII)) &&
+	      mac->set_if_mode)
 		mac->set_if_mode(mac, fm_eth->enet_if, SPEED_100);
 
 	/* init bmi rx port, IM mode and disable */
diff --git a/drivers/net/fm/memac.c b/drivers/net/fm/memac.c
index 144e109..592a67f 100644
--- a/drivers/net/fm/memac.c
+++ b/drivers/net/fm/memac.c
@@ -90,6 +90,7 @@
 		if_mode |= (IF_MODE_GMII | IF_MODE_RM);
 		break;
 	case PHY_INTERFACE_MODE_SGMII:
+	case PHY_INTERFACE_MODE_QSGMII:
 		if_mode &= ~IF_MODE_MASK;
 		if_mode |= (IF_MODE_GMII);
 		break;
diff --git a/drivers/net/fm/t4240.c b/drivers/net/fm/t4240.c
index 10c141f..6253f22 100644
--- a/drivers/net/fm/t4240.c
+++ b/drivers/net/fm/t4240.c
@@ -114,7 +114,45 @@
 			return PHY_INTERFACE_MODE_SGMII;
 		break;
 	default:
-		return PHY_INTERFACE_MODE_NONE;
+		break;
+	}
+
+	/* handle QSGMII */
+	switch (port) {
+	case FM1_DTSEC1:
+	case FM1_DTSEC2:
+	case FM1_DTSEC3:
+	case FM1_DTSEC4:
+		/* check lane G on SerDes1 */
+		if (is_serdes_configured(QSGMII_FM1_A))
+			return PHY_INTERFACE_MODE_QSGMII;
+		break;
+	case FM1_DTSEC5:
+	case FM1_DTSEC6:
+	case FM1_DTSEC9:
+	case FM1_DTSEC10:
+		/* check lane C on SerDes1 */
+		if (is_serdes_configured(QSGMII_FM1_B))
+			return PHY_INTERFACE_MODE_QSGMII;
+		break;
+	case FM2_DTSEC1:
+	case FM2_DTSEC2:
+	case FM2_DTSEC3:
+	case FM2_DTSEC4:
+		/* check lane G on SerDes2 */
+		if (is_serdes_configured(QSGMII_FM2_A))
+			return PHY_INTERFACE_MODE_QSGMII;
+		break;
+	case FM2_DTSEC5:
+	case FM2_DTSEC6:
+	case FM2_DTSEC9:
+	case FM2_DTSEC10:
+		/* check lane C on SerDes2 */
+		if (is_serdes_configured(QSGMII_FM2_B))
+			return PHY_INTERFACE_MODE_QSGMII;
+		break;
+	default:
+		break;
 	}
 
 	return PHY_INTERFACE_MODE_NONE;