MLK-16005-1 drivers: soc: refine the imx8 soc revision support
authorJason Liu <jason.hui.liu@nxp.com>
Thu, 13 Jul 2017 02:40:54 +0000 (10:40 +0800)
committerNitin Garg <nitin.garg@nxp.com>
Mon, 19 Mar 2018 20:33:37 +0000 (15:33 -0500)
This patch is to refine the imx8 soc revision support. The imx8qm and
imx8qxp will go through the SCU API to get the silicon ID and REVISION.
imx8mq will go through the anatop interface to get the ID/REV.

Since the silicon ID/REV need be set as early as possible, thus refine it
by using the early_initcall for the early initialization. For the SCU API
interface, this need be called after the MU interface initialized.

Signed-off-by: Jason Liu <jason.hui.liu@nxp.com>
Reviewed-by: Anson Huang <anson.huang@nxp.com>
drivers/soc/imx/Kconfig
drivers/soc/imx/Makefile
drivers/soc/imx/soc-imx8.c
include/soc/imx8/soc.h [new file with mode: 0644]

index 574af07..a590bea 100644 (file)
@@ -15,26 +15,26 @@ config ARCH_FSL_IMX8QM
        bool "i.MX8QM"
        select HAVE_IMX_MU
        select HAVE_IMX_RPMSG
-       select HAVE_IMX_SOC
+       select HAVE_IMX8_SOC
 
 config ARCH_FSL_IMX8QXP
        bool "i.MX8QXP"
        select HAVE_IMX_MU
        select HAVE_IMX_RPMSG
-       select HAVE_IMX_SOC
+       select HAVE_IMX8_SOC
 
 config ARCH_FSL_IMX8MQ
        bool "i.MX8MQ"
        select HAVE_IMX_MU
        select HAVE_IMX_RPMSG
-       select HAVE_IMX_SOC
+       select HAVE_IMX8_SOC
 
 endif
 
 config HAVE_IMX_MU
        bool
 
-config HAVE_IMX_SOC
+config HAVE_IMX8_SOC
        bool
 
 config HAVE_IMX_RPMSG
index e936043..1226985 100644 (file)
@@ -2,4 +2,4 @@ obj-$(CONFIG_HAVE_IMX_MU) += mu/
 obj-$(CONFIG_ARCH_FSL_IMX8QM) += sc/
 obj-$(CONFIG_ARCH_FSL_IMX8QM) += pm-domains.o
 obj-$(CONFIG_ARCH_FSL_IMX8MQ) += gpc-psci.o
-obj-$(CONFIG_HAVE_IMX_SOC) += soc-imx8.o
+obj-$(CONFIG_HAVE_IMX8_SOC) += soc-imx8.o
index 26823c3..7373337 100644 (file)
 #include <linux/platform_device.h>
 #include <linux/of.h>
 
+#include <soc/imx8/sc/sci.h>
+#include <soc/imx8/soc.h>
+#include <soc/imx/revision.h>
+
 #define ANADIG_DIGPROG         0x6c
 
 struct imx8_soc_data {
@@ -28,37 +32,47 @@ struct imx8_soc_data {
        u32 (*soc_revision)(void);
 };
 
-u32 imx8qm_soc_revision(void);
-u32 imx8qxp_soc_revision(void);
-u32 imx8mq_soc_revision(void);
+static u32 imx8_soc_id;
+static u32 imx8_soc_rev = IMX_CHIP_REVISION_UNKNOWN;
 
-struct imx8_soc_data imx8qm_soc_data = {
-       .name = "i.MX8QM",
-       .soc_revision = imx8qm_soc_revision,
-};
+static const struct imx8_soc_data *soc_data;
 
-struct imx8_soc_data imx8qxp_soc_data = {
-       .name = "i.MX8QXP",
-       .soc_revision = imx8qxp_soc_revision,
-};
+static inline void imx8_set_soc_revision(u32 rev)
+{
+       imx8_soc_rev = rev;
+}
 
-struct imx8_soc_data imx8mq_soc_data = {
-       .name = "i.MX8MQ",
-       .soc_revision = imx8mq_soc_revision,
-};
+unsigned int imx8_get_soc_revision(void)
+{
+       return imx8_soc_rev;
+}
 
-static const struct of_device_id imx8_soc_match[] = {
-       { .compatible = "fsl,imx8qm", .data = &imx8qm_soc_data, },
-       { .compatible = "fsl,imx8qxp", .data = &imx8qxp_soc_data, },
-       { .compatible = "fsl,imx8mq", .data = &imx8mq_soc_data, },
-       { }
-};
+static inline void imx8_set_soc_id(u32 id)
+{
+       imx8_soc_id = id;
+}
+
+inline bool cpu_is_imx8qm(void)
+{
+       return imx8_soc_id == IMX_SOC_IMX8QM;
+}
+
+inline bool cpu_is_imx8qxp(void)
+{
+       return imx8_soc_id == IMX_SOC_IMX8QXP;
+}
+
+inline bool cpu_is_imx8mq(void)
+{
+       return imx8_soc_id == IMX_SOC_IMX8MQ;
+}
 
-static u32 __init imx_init_revision_from_anatop(void)
+static u32 imx_init_revision_from_anatop(void)
 {
        struct device_node *np;
        void __iomem *anatop_base;
        u32 digprog;
+       u32 id, rev;
 
        np = of_find_compatible_node(NULL, NULL, "fsl,imx8mq-anatop");
        anatop_base = of_iomap(np, 0);
@@ -67,69 +81,149 @@ static u32 __init imx_init_revision_from_anatop(void)
        iounmap(anatop_base);
 
        /*
+        * Bit [23:16] is the silicon ID
         * Bit[7:4] is the base layer revision,
         * Bit[3:0] is the metal layer revision
         * e.g. 0x10 stands for Tapeout 1.0
         */
-       return digprog & 0xff;
+
+       rev = digprog & 0xff;
+       id = digprog >> 16 & 0xff;
+
+       imx8_set_soc_id(id);
+       imx8_set_soc_revision(rev);
+
+       return rev;
 }
 
-u32 imx8qm_soc_revision(void)
+static u32 imx_init_revision_from_scu(void)
 {
-       /*FIX ME later */
+       uint32_t mu_id;
+       sc_err_t sc_err = SC_ERR_NONE;
+       sc_ipc_t ipc_handle;
+       u32 id, rev;
+
+       sc_err = sc_ipc_getMuID(&mu_id);
+       if (sc_err != SC_ERR_NONE) {
+               WARN(1, "%s: Cannot obtain MU ID\n", __func__);
+
+               return IMX_CHIP_REVISION_UNKNOWN;
+       }
+
+       sc_err = sc_ipc_open(&ipc_handle, mu_id);
+       if (sc_err != SC_ERR_NONE) {
+               WARN(1, "%s: Cannot open MU channel\n", __func__);
+
+               return IMX_CHIP_REVISION_UNKNOWN;
+       };
+
+       sc_err = sc_misc_get_control(ipc_handle, SC_R_SC_PID0, SC_C_ID, &id);
+       if (sc_err != SC_ERR_NONE) {
+               WARN(1, "%s: Cannot get control\n", __func__);
+
+               return IMX_CHIP_REVISION_UNKNOWN;
+       };
+
+       rev = (id >> 5) & 0xf;
+       rev = (((rev >> 2) + 1) << 4) | (rev & 0x3);
+       id &= 0x1f;
 
-       return 0x10;
+       imx8_set_soc_id(id);
+       imx8_set_soc_revision(rev);
+
+       return rev;
 }
 
-u32 imx8qxp_soc_revision(void)
+static u32 imx8qm_soc_revision(void)
 {
-       /*FIX ME later */
+       return imx_init_revision_from_scu();
+}
 
-       return 0x10;
+static u32 imx8qxp_soc_revision(void)
+{
+       return imx_init_revision_from_scu();
 }
 
-u32 imx8mq_soc_revision(void)
+static u32 imx8mq_soc_revision(void)
 {
        return imx_init_revision_from_anatop();
 }
 
-static int __init imx8_soc_init(void)
+static struct imx8_soc_data imx8qm_soc_data = {
+       .name = "i.MX8QM",
+       .soc_revision = imx8qm_soc_revision,
+};
+
+static struct imx8_soc_data imx8qxp_soc_data = {
+       .name = "i.MX8QXP",
+       .soc_revision = imx8qxp_soc_revision,
+};
+
+static struct imx8_soc_data imx8mq_soc_data = {
+       .name = "i.MX8MQ",
+       .soc_revision = imx8mq_soc_revision,
+};
+
+static const struct of_device_id imx8_soc_match[] = {
+       { .compatible = "fsl,imx8qm", .data = &imx8qm_soc_data, },
+       { .compatible = "fsl,imx8qxp", .data = &imx8qxp_soc_data, },
+       { .compatible = "fsl,imx8mq", .data = &imx8mq_soc_data, },
+       { }
+};
+
+static int __init imx8_revision_init(void)
 {
-       struct soc_device_attribute *soc_dev_attr;
-       struct soc_device *soc_dev;
        struct device_node *root;
        const struct of_device_id *id;
-       u32 imx_soc_revision = 0;
-       const struct imx8_soc_data *data;
+       const char *machine;
+       u32 rev = IMX_CHIP_REVISION_UNKNOWN;
        int ret;
 
-       soc_dev_attr = kzalloc(sizeof(*soc_dev_attr), GFP_KERNEL);
-       if (!soc_dev_attr)
-               return -ENODEV;
-
-       soc_dev_attr->family = "Freescale i.MX";
-
        root = of_find_node_by_path("/");
-       ret = of_property_read_string(root, "model", &soc_dev_attr->machine);
+       ret = of_property_read_string(root, "model", &machine);
        if (ret)
-               goto free_soc;
+               return -ENODEV;
 
        id = of_match_node(imx8_soc_match, root);
        if (!id)
-               goto free_soc;
+               return -ENODEV;
 
        of_node_put(root);
 
-       data = id->data;
-       if (data) {
-               soc_dev_attr->soc_id = data->name;
-               if (data->soc_revision)
-                       imx_soc_revision = data->soc_revision();
-       }
+       soc_data = id->data;
+       if (soc_data && soc_data->soc_revision)
+               rev = soc_data->soc_revision();
+
+       if (rev == IMX_CHIP_REVISION_UNKNOWN)
+               pr_info("CPU identified as %s, unknown revision\n",
+                       soc_data->name);
+       else
+               pr_info("CPU identified as %s, silicon rev %d.%d\n",
+                       soc_data->name, (rev >> 4) & 0xf, rev & 0xf);
+
+       return 0;
+}
+early_initcall(imx8_revision_init);
+
+static int __init imx8_soc_init(void)
+{
+       struct soc_device_attribute *soc_dev_attr;
+       struct soc_device *soc_dev;
+       u32 soc_rev;
+
+       soc_dev_attr = kzalloc(sizeof(*soc_dev_attr), GFP_KERNEL);
+       if (!soc_dev_attr)
+               return -ENODEV;
+
+       soc_dev_attr->family = "Freescale i.MX";
+
+       if (soc_data)
+               soc_dev_attr->soc_id = soc_data->name;
 
+       soc_rev = imx8_get_soc_revision();
        soc_dev_attr->revision = kasprintf(GFP_KERNEL, "%d.%d",
-                                          (imx_soc_revision >> 4) & 0xf,
-                                          imx_soc_revision & 0xf);
+                                          (soc_rev >> 4) & 0xf,
+                                           soc_rev & 0xf);
        if (!soc_dev_attr->revision)
                goto free_soc;
 
diff --git a/include/soc/imx8/soc.h b/include/soc/imx8/soc.h
new file mode 100644 (file)
index 0000000..70c75fa
--- /dev/null
@@ -0,0 +1,30 @@
+/*
+ * Copyright 2017 NXP
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+
+#ifndef __SOC_IMX8_SOC_H__
+#define __SOC_IMX8_SOC_H__
+
+#define IMX_SOC_IMX8QM         0x01
+#define IMX_SOC_IMX8QXP                0x02
+#define IMX_SOC_IMX8MQ         0x82
+
+bool cpu_is_imx8qm(void);
+bool cpu_is_imx8mq(void);
+bool cpu_is_imx8qxp(void);
+
+extern bool TKT340553_SW_WORKAROUND;
+unsigned int imx8_get_soc_revision(void);
+
+#endif