board: fsl: lx2160ardb: add dts fixup function for RevC and newer

Since the new RevC LX2160A-RDB board has its 10G Aquantia PHYs at
different MDIO bus addresses, we must update both the kernel DTS and
u-boot's DTS (in case of DM_ETH) in case the board is indeed RevC or
newer. Use the newly introduced get_board_rev() function to trigger a
fixup of the kernel DTS to properly match the actual PHY addresses.
All this is encapsulated in the fdt_fixup_board_phy_revc() function
which will be used in the next patch.

Use the newly fdt_fixup_board_phy_revc() function introduced to
update both kernel's DTS and u-boot's DTS.

Signed-off-by: Florin Chiculita <florinlaurentiu.chiculita@nxp.com>
Signed-off-by: Ioana Ciornei <ioana.ciornei@nxp.com>
Reviewed-by: Peng Fan <peng.fan@nxp.com>
Signed-off-by: Peng Fan <peng.fan@nxp.com>
diff --git a/board/freescale/lx2160a/eth_lx2160ardb.c b/board/freescale/lx2160a/eth_lx2160ardb.c
index 533f606..c5dfefe 100644
--- a/board/freescale/lx2160a/eth_lx2160ardb.c
+++ b/board/freescale/lx2160a/eth_lx2160ardb.c
@@ -8,6 +8,7 @@
 #include <netdev.h>
 #include <exports.h>
 #include <fsl-mc/fsl_mc.h>
+#include "lx2160a.h"
 
 DECLARE_GLOBAL_DATA_PTR;
 
@@ -36,3 +37,109 @@
 #endif
 }
 #endif /* CONFIG_RESET_PHY_R */
+
+static int fdt_get_dpmac_node(void *fdt, int dpmac_id)
+{
+	char dpmac_str[11] = "dpmacs@00";
+	int offset, dpmacs_offset;
+
+	/* get the dpmac offset */
+	dpmacs_offset = fdt_path_offset(fdt, "/soc/fsl-mc/dpmacs");
+	if (dpmacs_offset < 0)
+		dpmacs_offset = fdt_path_offset(fdt, "/fsl-mc/dpmacs");
+
+	if (dpmacs_offset < 0) {
+		printf("dpmacs node not found in device tree\n");
+		return dpmacs_offset;
+	}
+
+	sprintf(dpmac_str, "dpmac@%x", dpmac_id);
+	offset = fdt_subnode_offset(fdt, dpmacs_offset, dpmac_str);
+	if (offset < 0) {
+		sprintf(dpmac_str, "ethernet@%x", dpmac_id);
+		offset = fdt_subnode_offset(fdt, dpmacs_offset, dpmac_str);
+		if (offset < 0) {
+			printf("dpmac@%x/ethernet@%x node not found in device tree\n",
+			       dpmac_id, dpmac_id);
+			return offset;
+		}
+	}
+
+	return offset;
+}
+
+static int fdt_update_phy_addr(void *fdt, int dpmac_id, int phy_addr)
+{
+	char dpmac_str[] = "dpmacs@00";
+	const u32 *phyhandle;
+	int offset;
+	int err;
+
+	/* get the dpmac offset */
+	offset = fdt_get_dpmac_node(fdt, dpmac_id);
+	if (offset < 0)
+		return offset;
+
+	/* get dpmac phy-handle */
+	sprintf(dpmac_str, "dpmac@%x", dpmac_id);
+	phyhandle = (u32 *)fdt_getprop(fdt, offset, "phy-handle", NULL);
+	if (!phyhandle) {
+		printf("%s node not found in device tree\n", dpmac_str);
+		return offset;
+	}
+
+	offset = fdt_node_offset_by_phandle(fdt, fdt32_to_cpu(*phyhandle));
+	if (offset < 0) {
+		printf("Could not get the ph node offset for dpmac %d\n",
+		       dpmac_id);
+		return offset;
+	}
+
+	phy_addr = cpu_to_fdt32(phy_addr);
+	err = fdt_setprop(fdt, offset, "reg", &phy_addr, sizeof(phy_addr));
+	if (err < 0) {
+		printf("Could not set phy node's reg for dpmac %d: %s.\n",
+		       dpmac_id, fdt_strerror(err));
+		return err;
+	}
+
+	return 0;
+}
+
+static int fdt_delete_phy_handle(void *fdt, int dpmac_id)
+{
+	const u32 *phyhandle;
+	int offset;
+
+	/* get the dpmac offset */
+	offset = fdt_get_dpmac_node(fdt, dpmac_id);
+	if (offset < 0)
+		return offset;
+
+	/* verify if the node has a phy-handle */
+	phyhandle = (u32 *)fdt_getprop(fdt, offset, "phy-handle", NULL);
+	if (!phyhandle)
+		return 0;
+
+	return fdt_delprop(fdt, offset, "phy-handle");
+}
+
+int fdt_fixup_board_phy_revc(void *fdt)
+{
+	int ret;
+
+	if (get_board_rev() < 'C')
+		return 0;
+
+	/* DPMACs 3,4 have their Aquantia PHYs at new addresses */
+	ret = fdt_update_phy_addr(fdt, 3, AQR113C_PHY_ADDR1);
+	if (ret)
+		return ret;
+
+	ret = fdt_update_phy_addr(fdt, 4, AQR113C_PHY_ADDR2);
+	if (ret)
+		return ret;
+
+	/* There is no PHY for the DPMAC2, so remove the phy-handle */
+	return fdt_delete_phy_handle(fdt, 2);
+}