summaryrefslogtreecommitdiff
path: root/arch/arm/mach-imx/imx8m
diff options
context:
space:
mode:
authorPeng Fan <peng.fan@nxp.com>2020-07-09 14:06:49 +0800
committerPeng Fan <peng.fan@nxp.com>2020-07-14 15:23:47 +0800
commit6036dba1c82b751fbea3ac2e1ddcd0e70729c402 (patch)
tree9833dd9276e1729fdbf5efefdd794d605beab64a /arch/arm/mach-imx/imx8m
parent2707faf01f04ee24b297e9da8988f4d05e971735 (diff)
imx8m: disable nodes before kernel/mfgtool boot for fused part
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@nxp.com>
Diffstat (limited to 'arch/arm/mach-imx/imx8m')
-rw-r--r--arch/arm/mach-imx/imx8m/soc.c333
1 files changed, 333 insertions, 0 deletions
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@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@30A00000",
+ "/mipi_dsi_bridge@30A00000",
+ "/dsi_phy@30A00300",
+ "/soc@0/bus@30800000/mipi_dsi@30a00000",
+ "/soc@0/bus@30800000/dphy@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@0x32e00000",
+ "/dcss@32e00000",
+ "/hdmi@32c00000",
+ "/hdmi_cec@32c33800",
+ "/hdmi_drm@32c00000",
+ "/display-subsystem",
+ "/sound-hdmi",
+ "/sound-hdmi-arc",
+ "/soc@0/bus@32c00000/display-controller@32e00000",
+ "/soc@0/bus@32c00000/hdmi@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@30320000",
+ "/soc@0/bus@30000000/lcdif@30320000"
+ };
+ static const char * const mipi_dsi_path[] = {
+ "/mipi_dsi@30A00000",
+ "/soc@0/bus@30800000/mipi_dsi@30a00000"
+ };
+ static const char * const lcdif_ep_path[] = {
+ "/lcdif@30320000/port@0/mipi-dsi-endpoint",
+ "/soc@0/bus@30000000/lcdif@30320000/port@0/endpoint"
+ };
+ static const char * const mipi_dsi_ep_path[] = {
+ "/mipi_dsi@30A00000/port@1/endpoint",
+ "/soc@0/bus@30800000/mipi_dsi@30a00000/ports/port@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@38300000",
+ "/soc@0/vpu@38300000"
+ };
+
+ static const char * const nodes_path_8mm[] = {
+ "/vpu_g1@38300000",
+ "/vpu_g2@38310000",
+ "/vpu_h1@38320000"
+ };
+
+ static const char * const nodes_path_8mp[] = {
+ "/vpu_g1@38300000",
+ "/vpu_g2@38310000",
+ "/vpu_vc8000e@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@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@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@0/bus@32c00000/camera/isp@32e10000",
+ "/soc@0/bus@32c00000/camera/isp@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@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@1",
+ "/cpus/cpu@2",
+ "/cpus/cpu@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@38100000/dwc3",
+ "/soc@0/usb@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