diff mbox series

[09/11] imx8m: disable nodes before kernel/mfgtool boot for fused part

Message ID 20200709084042.8234-10-peng.fan@nxp.com
State Accepted
Commit 6036dba1c82b751fbea3ac2e1ddcd0e70729c402
Headers show
Series imx8m: soc/clk update | expand

Commit Message

Peng Fan July 9, 2020, 8:40 a.m. UTC
From: Peng Fan <peng.fan at nxp.com>

To fused part, we need to disable nodes of dtb to let kernel boot.

To mfgtool, USB issue when using super-speed for mfgtool, temporally
work around the problem to use high-speed only.

Signed-off-by: Peng Fan <peng.fan at nxp.com>
---
 arch/arm/mach-imx/imx8m/soc.c | 333 ++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 333 insertions(+)
diff mbox series

Patch

diff --git a/arch/arm/mach-imx/imx8m/soc.c b/arch/arm/mach-imx/imx8m/soc.c
index 9517a7cfcf..bb2f112af6 100644
--- a/arch/arm/mach-imx/imx8m/soc.c
+++ b/arch/arm/mach-imx/imx8m/soc.c
@@ -428,12 +428,298 @@  bool is_usb_boot(void)
 }
 
 #ifdef CONFIG_OF_SYSTEM_SETUP
+bool check_fdt_new_path(void *blob)
+{
+	const char *soc_path = "/soc at 0";
+	int nodeoff;
+
+	nodeoff = fdt_path_offset(blob, soc_path);
+	if (nodeoff < 0)
+		return false;
+
+	return true;
+}
+
+static int disable_fdt_nodes(void *blob, const char *const nodes_path[], int size_array)
+{
+	int i = 0;
+	int rc;
+	int nodeoff;
+	const char *status = "disabled";
+
+	for (i = 0; i < size_array; i++) {
+		nodeoff = fdt_path_offset(blob, nodes_path[i]);
+		if (nodeoff < 0)
+			continue; /* Not found, skip it */
+
+		printf("Found %s node\n", nodes_path[i]);
+
+add_status:
+		rc = fdt_setprop(blob, nodeoff, "status", status, strlen(status) + 1);
+		if (rc) {
+			if (rc == -FDT_ERR_NOSPACE) {
+				rc = fdt_increase_size(blob, 512);
+				if (!rc)
+					goto add_status;
+			}
+			printf("Unable to update property %s:%s, err=%s\n",
+			       nodes_path[i], "status", fdt_strerror(rc));
+		} else {
+			printf("Modify %s:%s disabled\n",
+			       nodes_path[i], "status");
+		}
+	}
+
+	return 0;
+}
+
+#ifdef CONFIG_IMX8MQ
+bool check_dcss_fused(void)
+{
+	struct ocotp_regs *ocotp = (struct ocotp_regs *)OCOTP_BASE_ADDR;
+	struct fuse_bank *bank = &ocotp->bank[1];
+	struct fuse_bank1_regs *fuse =
+		(struct fuse_bank1_regs *)bank->fuse_regs;
+	u32 value = readl(&fuse->tester4);
+
+	if (value & 0x4000000)
+		return true;
+
+	return false;
+}
+
+static int disable_mipi_dsi_nodes(void *blob)
+{
+	static const char * const nodes_path[] = {
+		"/mipi_dsi at 30A00000",
+		"/mipi_dsi_bridge at 30A00000",
+		"/dsi_phy at 30A00300",
+		"/soc at 0/bus at 30800000/mipi_dsi at 30a00000",
+		"/soc at 0/bus at 30800000/dphy at 30a00300"
+	};
+
+	return disable_fdt_nodes(blob, nodes_path, ARRAY_SIZE(nodes_path));
+}
+
+static int disable_dcss_nodes(void *blob)
+{
+	static const char * const nodes_path[] = {
+		"/dcss at 0x32e00000",
+		"/dcss at 32e00000",
+		"/hdmi at 32c00000",
+		"/hdmi_cec at 32c33800",
+		"/hdmi_drm at 32c00000",
+		"/display-subsystem",
+		"/sound-hdmi",
+		"/sound-hdmi-arc",
+		"/soc at 0/bus at 32c00000/display-controller at 32e00000",
+		"/soc at 0/bus at 32c00000/hdmi at 32c00000",
+	};
+
+	return disable_fdt_nodes(blob, nodes_path, ARRAY_SIZE(nodes_path));
+}
+
+static int check_mipi_dsi_nodes(void *blob)
+{
+	static const char * const lcdif_path[] = {
+		"/lcdif at 30320000",
+		"/soc at 0/bus at 30000000/lcdif at 30320000"
+	};
+	static const char * const mipi_dsi_path[] = {
+		"/mipi_dsi at 30A00000",
+		"/soc at 0/bus at 30800000/mipi_dsi at 30a00000"
+	};
+	static const char * const lcdif_ep_path[] = {
+		"/lcdif at 30320000/port at 0/mipi-dsi-endpoint",
+		"/soc at 0/bus at 30000000/lcdif at 30320000/port at 0/endpoint"
+	};
+	static const char * const mipi_dsi_ep_path[] = {
+		"/mipi_dsi at 30A00000/port at 1/endpoint",
+		"/soc at 0/bus at 30800000/mipi_dsi at 30a00000/ports/port at 0/endpoint"
+	};
+
+	int lookup_node;
+	int nodeoff;
+	bool new_path = check_fdt_new_path(blob);
+	int i = new_path ? 1 : 0;
+
+	nodeoff = fdt_path_offset(blob, lcdif_path[i]);
+	if (nodeoff < 0 || !fdtdec_get_is_enabled(blob, nodeoff)) {
+		/*
+		 * If can't find lcdif node or lcdif node is disabled,
+		 * then disable all mipi dsi, since they only can input
+		 * from DCSS
+		 */
+		return disable_mipi_dsi_nodes(blob);
+	}
+
+	nodeoff = fdt_path_offset(blob, mipi_dsi_path[i]);
+	if (nodeoff < 0 || !fdtdec_get_is_enabled(blob, nodeoff))
+		return 0;
+
+	nodeoff = fdt_path_offset(blob, lcdif_ep_path[i]);
+	if (nodeoff < 0) {
+		/*
+		 * If can't find lcdif endpoint, then disable all mipi dsi,
+		 * since they only can input from DCSS
+		 */
+		return disable_mipi_dsi_nodes(blob);
+	}
+
+	lookup_node = fdtdec_lookup_phandle(blob, nodeoff, "remote-endpoint");
+	nodeoff = fdt_path_offset(blob, mipi_dsi_ep_path[i]);
+
+	if (nodeoff > 0 && nodeoff == lookup_node)
+		return 0;
+
+	return disable_mipi_dsi_nodes(blob);
+}
+#endif
+
+int disable_vpu_nodes(void *blob)
+{
+	static const char * const nodes_path_8mq[] = {
+		"/vpu at 38300000",
+		"/soc at 0/vpu at 38300000"
+	};
+
+	static const char * const nodes_path_8mm[] = {
+		"/vpu_g1 at 38300000",
+		"/vpu_g2 at 38310000",
+		"/vpu_h1 at 38320000"
+	};
+
+	static const char * const nodes_path_8mp[] = {
+		"/vpu_g1 at 38300000",
+		"/vpu_g2 at 38310000",
+		"/vpu_vc8000e at 38320000"
+	};
+
+	if (is_imx8mq())
+		return disable_fdt_nodes(blob, nodes_path_8mq, ARRAY_SIZE(nodes_path_8mq));
+	else if (is_imx8mm())
+		return disable_fdt_nodes(blob, nodes_path_8mm, ARRAY_SIZE(nodes_path_8mm));
+	else if (is_imx8mp())
+		return disable_fdt_nodes(blob, nodes_path_8mp, ARRAY_SIZE(nodes_path_8mp));
+	else
+		return -EPERM;
+}
+
+int disable_gpu_nodes(void *blob)
+{
+	static const char * const nodes_path_8mn[] = {
+		"/gpu at 38000000"
+	};
+
+	return disable_fdt_nodes(blob, nodes_path_8mn, ARRAY_SIZE(nodes_path_8mn));
+}
+
+int disable_npu_nodes(void *blob)
+{
+	static const char * const nodes_path_8mp[] = {
+		"/vipsi at 38500000"
+	};
+
+	return disable_fdt_nodes(blob, nodes_path_8mp, ARRAY_SIZE(nodes_path_8mp));
+}
+
+int disable_isp_nodes(void *blob)
+{
+	static const char * const nodes_path_8mp[] = {
+		"/soc at 0/bus at 32c00000/camera/isp at 32e10000",
+		"/soc at 0/bus at 32c00000/camera/isp at 32e20000"
+	};
+
+	return disable_fdt_nodes(blob, nodes_path_8mp, ARRAY_SIZE(nodes_path_8mp));
+}
+
+int disable_dsp_nodes(void *blob)
+{
+	static const char * const nodes_path_8mp[] = {
+		"/dsp at 3b6e8000"
+	};
+
+	return disable_fdt_nodes(blob, nodes_path_8mp, ARRAY_SIZE(nodes_path_8mp));
+}
+
+static int disable_cpu_nodes(void *blob, u32 disabled_cores)
+{
+	static const char * const nodes_path[] = {
+		"/cpus/cpu at 1",
+		"/cpus/cpu at 2",
+		"/cpus/cpu at 3",
+	};
+	u32 i = 0;
+	int rc;
+	int nodeoff;
+
+	if (disabled_cores > 3)
+		return -EINVAL;
+
+	i = 3 - disabled_cores;
+
+	for (; i < 3; i++) {
+		nodeoff = fdt_path_offset(blob, nodes_path[i]);
+		if (nodeoff < 0)
+			continue; /* Not found, skip it */
+
+		debug("Found %s node\n", nodes_path[i]);
+
+		rc = fdt_del_node(blob, nodeoff);
+		if (rc < 0) {
+			printf("Unable to delete node %s, err=%s\n",
+			       nodes_path[i], fdt_strerror(rc));
+		} else {
+			printf("Delete node %s\n", nodes_path[i]);
+		}
+	}
+
+	return 0;
+}
+
 int ft_system_setup(void *blob, bd_t *bd)
 {
+#ifdef CONFIG_IMX8MQ
 	int i = 0;
 	int rc;
 	int nodeoff;
 
+	if (get_boot_device() == USB_BOOT) {
+		disable_dcss_nodes(blob);
+
+		bool new_path = check_fdt_new_path(blob);
+		int v = new_path ? 1 : 0;
+		static const char * const usb_dwc3_path[] = {
+			"/usb at 38100000/dwc3",
+			"/soc at 0/usb at 38100000"
+		};
+
+		nodeoff = fdt_path_offset(blob, usb_dwc3_path[v]);
+		if (nodeoff >= 0) {
+			const char *speed = "high-speed";
+
+			printf("Found %s node\n", usb_dwc3_path[v]);
+
+usb_modify_speed:
+
+			rc = fdt_setprop(blob, nodeoff, "maximum-speed", speed, strlen(speed) + 1);
+			if (rc) {
+				if (rc == -FDT_ERR_NOSPACE) {
+					rc = fdt_increase_size(blob, 512);
+					if (!rc)
+						goto usb_modify_speed;
+				}
+				printf("Unable to set property %s:%s, err=%s\n",
+				       usb_dwc3_path[v], "maximum-speed", fdt_strerror(rc));
+			} else {
+				printf("Modify %s:%s = %s\n",
+				       usb_dwc3_path[v], "maximum-speed", speed);
+			}
+		} else {
+			printf("Can't found %s node\n", usb_dwc3_path[v]);
+		}
+	}
+
 	/* Disable the CPU idle for A0 chip since the HW does not support it */
 	if (is_soc_rev(CHIP_REV_1_0)) {
 		static const char * const nodes_path[] = {
@@ -464,6 +750,53 @@  int ft_system_setup(void *blob, bd_t *bd)
 		}
 	}
 
+	if (is_imx8mql()) {
+		disable_vpu_nodes(blob);
+		if (check_dcss_fused()) {
+			printf("DCSS is fused\n");
+			disable_dcss_nodes(blob);
+			check_mipi_dsi_nodes(blob);
+		}
+	}
+
+	if (is_imx8md())
+		disable_cpu_nodes(blob, 2);
+
+#elif defined(CONFIG_IMX8MM)
+	if (is_imx8mml() || is_imx8mmdl() ||  is_imx8mmsl())
+		disable_vpu_nodes(blob);
+
+	if (is_imx8mmd() || is_imx8mmdl())
+		disable_cpu_nodes(blob, 2);
+	else if (is_imx8mms() || is_imx8mmsl())
+		disable_cpu_nodes(blob, 3);
+
+#elif defined(CONFIG_IMX8MN)
+	if (is_imx8mnl() || is_imx8mndl() ||  is_imx8mnsl())
+		disable_gpu_nodes(blob);
+
+	if (is_imx8mnd() || is_imx8mndl())
+		disable_cpu_nodes(blob, 2);
+	else if (is_imx8mns() || is_imx8mnsl())
+		disable_cpu_nodes(blob, 3);
+
+#elif defined(CONFIG_IMX8MP)
+	if (is_imx8mpl() || is_imx8mp7())
+		disable_vpu_nodes(blob);
+
+	if (is_imx8mpl() || is_imx8mp6() || is_imx8mp5())
+		disable_npu_nodes(blob);
+
+	if (is_imx8mpl() || is_imx8mp5())
+		disable_isp_nodes(blob);
+
+	if (is_imx8mpl() || is_imx8mp7() || is_imx8mp6() || is_imx8mp5())
+		disable_dsp_nodes(blob);
+
+	if (is_imx8mpd())
+		disable_cpu_nodes(blob, 2);
+#endif
+
 	return 0;
 }
 #endif