cpufreq: imx6sx/imx6q: read OCOTP through nvmem for imx6sx/imx6q
authorArulpandiyan Vadivel <arulpandiyan_vadivel@mentor.com>
Tue, 16 Apr 2019 06:10:05 +0000 (11:40 +0530)
committerLeonard Crestez <leonard.crestez@nxp.com>
Thu, 18 Apr 2019 00:00:38 +0000 (03:00 +0300)
On i.MX6SX/i.MX6Q, accessing OCOTP directly is wrong because
the ocotp clock needs to be enabled first. Add support for reading
OCOTP through the nvmem API, and keep the old method there to
support old dtb.

Signed-off-by: Arulpandiyan Vadivel <arulpandiyan_vadivel@mentor.com>
(cherry picked from commit 766bc770f5fc12dd85aa8b26c53ac310afb9e24b)

drivers/cpufreq/imx6q-cpufreq.c

index 31a08b0..1f7e58c 100644 (file)
@@ -313,20 +313,31 @@ static struct cpufreq_driver imx6q_cpufreq_driver = {
 #define OCOTP_CFG3_SPEED_996MHZ                0x2
 #define OCOTP_CFG3_SPEED_852MHZ                0x1
 
-static void imx6q_opp_check_speed_grading(struct device *dev)
+static int imx6q_opp_check_speed_grading(struct device *dev)
 {
-       struct device_node *np;
-       void __iomem *base;
        u32 val;
+       int ret = 0;
+
+       if (of_find_property(dev->of_node, "nvmem-cells", NULL)) {
+               ret = nvmem_cell_read_u32(dev, "speed_grade", &val);
+               if (ret)
+                       return ret;
+       } else {
+               struct device_node *np;
+               void __iomem *base;
 
-       np = of_find_compatible_node(NULL, NULL, "fsl,imx6q-ocotp");
-       if (!np)
-               return;
+               np = of_find_compatible_node(NULL, NULL, "fsl,imx6q-ocotp");
+               if (!np)
+                       return -ENOENT;
 
-       base = of_iomap(np, 0);
-       if (!base) {
-               dev_err(dev, "failed to map ocotp\n");
-               goto put_node;
+               base = of_iomap(np, 0);
+               of_node_put(np);
+               if (!base) {
+                       dev_err(dev, "failed to map ocotp\n");
+                       return -EFAULT;
+               }
+               val = readl_relaxed(base + OCOTP_CFG3);
+               iounmap(base);
        }
 
        /*
@@ -337,7 +348,6 @@ static void imx6q_opp_check_speed_grading(struct device *dev)
         * 2b'00: 792000000Hz;
         * We need to set the max speed of ARM according to fuse map.
         */
-       val = readl_relaxed(base + OCOTP_CFG3);
        val >>= OCOTP_CFG3_SPEED_SHIFT;
        val &= 0x3;
 
@@ -354,16 +364,13 @@ static void imx6q_opp_check_speed_grading(struct device *dev)
                        if (dev_pm_opp_disable(dev, 1200000000))
                                dev_warn(dev, "failed to disable 1.2GHz OPP\n");
        }
-       iounmap(base);
 
        if (IS_ENABLED(CONFIG_MX6_VPU_352M)) {
                if (dev_pm_opp_disable(cpu_dev, 396000000))
                        pr_warn("failed to disable 396MHz OPP\n");
                pr_info("remove 396MHz OPP for VPU running at 352MHz!\n");
        }
-
-put_node:
-       of_node_put(np);
+       return ret;
 }
 
 #define OCOTP_CFG3_6UL_SPEED_696MHZ    0x2
@@ -555,7 +562,14 @@ static int imx6q_cpufreq_probe(struct platform_device *pdev)
                        return ret;
                }
        } else {
-               imx6q_opp_check_speed_grading(cpu_dev);
+               ret = imx6q_opp_check_speed_grading(cpu_dev);
+               if (ret == -EPROBE_DEFER)
+                       return ret;
+               if (ret) {
+                       dev_err(cpu_dev, "failed to read ocotp: %d\n",
+                               ret);
+                       return ret;
+               }
        }
 
        /* Because we have added the OPPs here, we must free them */