From fa58327c8fdfc640a1411f624fa5d367ad888e43 Mon Sep 17 00:00:00 2001 From: Marek Vasut Date: Sat, 11 Feb 2023 23:10:50 +0100 Subject: [PATCH] arm64: imx8mp: Auto-detect PHY on i.MX8MP DHCOM The i.MX8MP DHCOM SoM may be populated with either KSZ9131RNXI RGMII PHY or LAN8740Ai RMII PHY attached to EQoS MAC, and either external RGMII PHY or LAN8740Ai RMII PHY attached to FEC MAC. The SoM configuration can be detected for each MAC by reading RX_CTL pull resistor state early on boot. Make use of this, detect the exact PHY configuration, and patch control DT accordingly so that the ethernet is configured correctly in U-Boot. Signed-off-by: Marek Vasut --- .../dh_imx8mp/imx8mp_dhcom_pdk2.c | 228 ++++++++++++++++++ 1 file changed, 228 insertions(+) diff --git a/board/dhelectronics/dh_imx8mp/imx8mp_dhcom_pdk2.c b/board/dhelectronics/dh_imx8mp/imx8mp_dhcom_pdk2.c index 9d8e19d994..c690a5a828 100644 --- a/board/dhelectronics/dh_imx8mp/imx8mp_dhcom_pdk2.c +++ b/board/dhelectronics/dh_imx8mp/imx8mp_dhcom_pdk2.c @@ -5,12 +5,16 @@ #include #include +#include +#include #include #include #include +#include #include #include #include +#include #include #include #include @@ -142,3 +146,227 @@ enum env_location env_get_location(enum env_operation op, int prio) { return prio ? ENVL_UNKNOWN : ENVL_SPI_FLASH; } + +static const char *iomuxc_compat = "fsl,imx8mp-iomuxc"; +static const char *lan_compat = "ethernet-phy-id0007.c110"; +static const char *ksz_compat = "ethernet-phy-id0022.1642"; + +static int dh_dt_patch_som_eqos(const void *fdt_blob) +{ + const void __iomem *mux = (void __iomem *)IOMUXC_BASE_ADDR + + FIELD_GET(MUX_CTRL_OFS_MASK, MX8MP_PAD_ENET_RX_CTL__GPIO1_IO24); + int mac_node, mdio_node, iomuxc_node, ksz_node, lan_node, subnode; + const char *mac_compat = "nxp,imx8mp-dwmac-eqos"; + void *blob = (void *)fdt_blob; + const fdt32_t *clk_prop; + bool is_gigabit; + u32 handle; + u32 clk[6]; + + setbits_le32(mux, IOMUX_CONFIG_SION); + is_gigabit = !(readl(GPIO1_BASE_ADDR) & BIT(24)); + clrbits_le32(mux, IOMUX_CONFIG_SION); + + /* Adjust EQoS node for Gigabit KSZ9131RNXI or Fast LAN8740Ai PHY */ + mac_node = fdt_node_offset_by_compatible(blob, -1, mac_compat); + if (mac_node < 0) + return 0; + + mdio_node = fdt_first_subnode(blob, mac_node); + if (mdio_node < 0) + return 0; + + /* KSZ9131RNXI */ + ksz_node = fdt_node_offset_by_compatible(blob, mdio_node, ksz_compat); + if (ksz_node < 0) + return 0; + + /* LAN8740Ai */ + lan_node = fdt_node_offset_by_compatible(blob, mdio_node, lan_compat); + if (lan_node < 0) + return 0; + + iomuxc_node = fdt_node_offset_by_compatible(blob, -1, iomuxc_compat); + if (iomuxc_node < 0) + return 0; + + /* + * The code below adjusts the following DT properties: + * - assigned-clock-parents .. 125 MHz RGMII / 50 MHz RMII ref clock + * - assigned-clock-rates .... 125 MHz RGMII / 50 MHz RMII ref clock + * - phy-handle .............. KSZ9131RNXI RGMII / LAN8740Ai RMII + * - phy-mode ................ RGMII / RMII + * - pinctrl-0 ............... RGMII / RMII + * - PHY subnode status ...... "disabled"/"okay" per RGMII / RMII + */ + + /* Perform all inplace changes first, string changes last. */ + clk_prop = fdt_getprop(blob, mac_node, "assigned-clock-parents", NULL); + if (!clk_prop) + return 0; + clk[0] = clk_prop[0]; + clk[1] = cpu_to_fdt32(IMX8MP_SYS_PLL1_266M); + clk[2] = clk_prop[2]; + clk[3] = cpu_to_fdt32(IMX8MP_SYS_PLL2_100M); + clk[4] = clk_prop[4]; + clk[5] = is_gigabit ? cpu_to_fdt32(IMX8MP_SYS_PLL2_125M) : + cpu_to_fdt32(IMX8MP_SYS_PLL2_50M); + fdt_setprop_inplace(blob, mac_node, "assigned-clock-parents", + clk, 6 * sizeof(u32)); + + clk[0] = cpu_to_fdt32(0); + clk[1] = cpu_to_fdt32(100000000); + clk[2] = is_gigabit ? cpu_to_fdt32(125000000) : + cpu_to_fdt32(50000000); + fdt_setprop_inplace(blob, mac_node, "assigned-clock-rates", + clk, 3 * sizeof(u32)); + + handle = fdt_get_phandle(blob, is_gigabit ? ksz_node : lan_node); + fdt_setprop_inplace_u32(blob, mac_node, "phy-handle", handle); + + fdt_for_each_subnode(subnode, blob, iomuxc_node) { + if (!strstr(fdt_get_name(blob, subnode, NULL), + is_gigabit ? "eqos-rgmii" : "eqos-rmii")) + continue; + + handle = fdt_get_phandle(blob, subnode); + fdt_setprop_inplace_u32(blob, mac_node, "pinctrl-0", handle); + break; + } + + fdt_setprop_string(blob, mac_node, "phy-mode", + is_gigabit ? "rgmii-id" : "rmii"); + + mac_node = fdt_node_offset_by_compatible(blob, -1, mac_compat); + mdio_node = fdt_first_subnode(blob, mac_node); + ksz_node = fdt_node_offset_by_compatible(blob, mdio_node, ksz_compat); + fdt_setprop_string(blob, ksz_node, "status", + is_gigabit ? "okay" : "disabled"); + + mac_node = fdt_node_offset_by_compatible(blob, -1, mac_compat); + mdio_node = fdt_first_subnode(blob, mac_node); + lan_node = fdt_node_offset_by_compatible(blob, mdio_node, lan_compat); + fdt_setprop_string(blob, lan_node, "status", + is_gigabit ? "disabled" : "okay"); + + return 0; +} + +static int dh_dt_patch_som_fec(const void *fdt_blob) +{ + const void __iomem *mux = (void __iomem *)IOMUXC_BASE_ADDR + + FIELD_GET(MUX_CTRL_OFS_MASK, MX8MP_PAD_SAI1_TXFS__GPIO4_IO10); + int mac_node, mdio_node, iomuxc_node, lan_node, phy_node, subnode; + const char *mac_compat = "fsl,imx8mp-fec"; + void *blob = (void *)fdt_blob; + const fdt32_t *clk_prop; + bool is_gigabit; + u32 handle; + u32 clk[8]; + + setbits_le32(mux, IOMUX_CONFIG_SION); + is_gigabit = !(readl(GPIO4_BASE_ADDR) & BIT(10)); + clrbits_le32(mux, IOMUX_CONFIG_SION); + + /* Test for non-default SoM with 100/Full PHY attached to FEC */ + if (is_gigabit) + return 0; + + /* Adjust FEC node for Fast LAN8740Ai PHY */ + mac_node = fdt_node_offset_by_compatible(blob, -1, mac_compat); + if (mac_node < 0) + return 0; + + /* Optional PHY pointed to by phy-handle, possibly on carrier board */ + phy_node = fdtdec_lookup_phandle(blob, mac_node, "phy-handle"); + if (phy_node > 0) { + fdt_setprop_string(blob, phy_node, "status", "disabled"); + mac_node = fdt_node_offset_by_compatible(blob, -1, mac_compat); + } + + mdio_node = fdt_first_subnode(blob, mac_node); + if (mdio_node < 0) + return 0; + + /* LAN8740Ai */ + lan_node = fdt_node_offset_by_compatible(blob, mdio_node, lan_compat); + if (lan_node < 0) + return 0; + + iomuxc_node = fdt_node_offset_by_compatible(blob, -1, iomuxc_compat); + if (iomuxc_node < 0) + return 0; + + /* + * The code below adjusts the following DT properties: + * - assigned-clock-parents .. 50 MHz RMII ref clock + * - assigned-clock-rates .... 50 MHz RMII ref clock + * - phy-handle .............. LAN8740Ai RMII + * - phy-mode ................ RMII + * - pinctrl-0 ............... RMII + * - PHY subnode status ...... "okay" for RMII PHY + */ + + /* Perform all inplace changes first, string changes last. */ + clk_prop = fdt_getprop(blob, mac_node, "assigned-clock-parents", NULL); + if (!clk_prop) + return 0; + clk[0] = clk_prop[0]; + clk[1] = cpu_to_fdt32(IMX8MP_SYS_PLL1_266M); + clk[2] = clk_prop[2]; + clk[3] = cpu_to_fdt32(IMX8MP_SYS_PLL2_100M); + clk[4] = clk_prop[4]; + clk[5] = cpu_to_fdt32(IMX8MP_SYS_PLL2_50M); + clk[6] = clk_prop[6]; + clk[7] = cpu_to_fdt32(IMX8MP_SYS_PLL2_50M); + fdt_setprop_inplace(blob, mac_node, "assigned-clock-parents", + clk, 8 * sizeof(u32)); + + clk[0] = cpu_to_fdt32(0); + clk[1] = cpu_to_fdt32(100000000); + clk[2] = cpu_to_fdt32(50000000); + clk[3] = cpu_to_fdt32(0); + fdt_setprop_inplace(blob, mac_node, "assigned-clock-rates", + clk, 4 * sizeof(u32)); + + handle = fdt_get_phandle(blob, lan_node); + fdt_setprop_inplace_u32(blob, mac_node, "phy-handle", handle); + + fdt_for_each_subnode(subnode, blob, iomuxc_node) { + if (!strstr(fdt_get_name(blob, subnode, NULL), "fec-rmii")) + continue; + + handle = fdt_get_phandle(blob, subnode); + fdt_setprop_inplace_u32(blob, mac_node, "pinctrl-0", handle); + break; + } + + fdt_setprop_string(blob, mac_node, "phy-mode", "rmii"); + mac_node = fdt_node_offset_by_compatible(blob, -1, mac_compat); + mdio_node = fdt_first_subnode(blob, mac_node); + lan_node = fdt_node_offset_by_compatible(blob, mdio_node, lan_compat); + fdt_setprop_string(blob, lan_node, "status", "okay"); + + return 0; +} + +static int dh_dt_patch_som(const void *fdt_blob) +{ + int ret; + + /* Do nothing if not i.MX8MP DHCOM SoM */ + ret = fdt_node_check_compatible(fdt_blob, 0, "dh,imx8mp-dhcom-som"); + if (ret) + return 0; + + ret = dh_dt_patch_som_eqos(fdt_blob); + if (ret) + return ret; + + return dh_dt_patch_som_fec(fdt_blob); +} + +int fdtdec_board_setup(const void *fdt_blob) +{ + return dh_dt_patch_som(fdt_blob); +} -- 2.39.5