Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 4ef576e9 authored by Anson Huang's avatar Anson Huang Committed by Greg Kroah-Hartman
Browse files

cpufreq: imx6q: read OCOTP through nvmem for imx6ul/imx6ull



commit 2733fb0d0699246711cf622e0e2faf02a05b69dc upstream.

On i.MX6UL/i.MX6ULL, 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: default avatarAnson Huang <Anson.Huang@nxp.com>
Acked-by: default avatarViresh Kumar <viresh.kumar@linaro.org>
Signed-off-by: default avatarRafael J. Wysocki <rafael.j.wysocki@intel.com>
Cc: Sébastien Szymanski <sebastien.szymanski@armadeus.com>
Cc: Lucas Stach <l.stach@pengutronix.de>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent 0b9700de
Loading
Loading
Loading
Loading
+35 −17
Original line number Original line Diff line number Diff line
@@ -12,6 +12,7 @@
#include <linux/cpu_cooling.h>
#include <linux/cpu_cooling.h>
#include <linux/err.h>
#include <linux/err.h>
#include <linux/module.h>
#include <linux/module.h>
#include <linux/nvmem-consumer.h>
#include <linux/of.h>
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/of_address.h>
#include <linux/pm_opp.h>
#include <linux/pm_opp.h>
@@ -295,20 +296,32 @@ static void imx6q_opp_check_speed_grading(struct device *dev)
#define OCOTP_CFG3_6ULL_SPEED_792MHZ	0x2
#define OCOTP_CFG3_6ULL_SPEED_792MHZ	0x2
#define OCOTP_CFG3_6ULL_SPEED_900MHZ	0x3
#define OCOTP_CFG3_6ULL_SPEED_900MHZ	0x3


static void imx6ul_opp_check_speed_grading(struct device *dev)
static int imx6ul_opp_check_speed_grading(struct device *dev)
{
{
	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;
		struct device_node *np;
		void __iomem *base;
		void __iomem *base;
	u32 val;


		np = of_find_compatible_node(NULL, NULL, "fsl,imx6ul-ocotp");
		np = of_find_compatible_node(NULL, NULL, "fsl,imx6ul-ocotp");
		if (!np)
		if (!np)
		return;
			return -ENOENT;


		base = of_iomap(np, 0);
		base = of_iomap(np, 0);
		of_node_put(np);
		if (!base) {
		if (!base) {
			dev_err(dev, "failed to map ocotp\n");
			dev_err(dev, "failed to map ocotp\n");
		goto put_node;
			return -EFAULT;
		}

		val = readl_relaxed(base + OCOTP_CFG3);
		iounmap(base);
	}
	}


	/*
	/*
@@ -319,7 +332,6 @@ static void imx6ul_opp_check_speed_grading(struct device *dev)
	 * 2b'11: 900000000Hz on i.MX6ULL only;
	 * 2b'11: 900000000Hz on i.MX6ULL only;
	 * We need to set the max speed of ARM according to fuse map.
	 * 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 >>= OCOTP_CFG3_SPEED_SHIFT;
	val &= 0x3;
	val &= 0x3;


@@ -339,9 +351,7 @@ static void imx6ul_opp_check_speed_grading(struct device *dev)
				dev_warn(dev, "failed to disable 900MHz OPP\n");
				dev_warn(dev, "failed to disable 900MHz OPP\n");
	}
	}


	iounmap(base);
	return ret;
put_node:
	of_node_put(np);
}
}


static int imx6q_cpufreq_probe(struct platform_device *pdev)
static int imx6q_cpufreq_probe(struct platform_device *pdev)
@@ -399,10 +409,18 @@ static int imx6q_cpufreq_probe(struct platform_device *pdev)
	}
	}


	if (of_machine_is_compatible("fsl,imx6ul") ||
	if (of_machine_is_compatible("fsl,imx6ul") ||
	    of_machine_is_compatible("fsl,imx6ull"))
	    of_machine_is_compatible("fsl,imx6ull")) {
		imx6ul_opp_check_speed_grading(cpu_dev);
		ret = imx6ul_opp_check_speed_grading(cpu_dev);
	else
		if (ret == -EPROBE_DEFER)
			return ret;
		if (ret) {
			dev_err(cpu_dev, "failed to read ocotp: %d\n",
				ret);
			return ret;
		}
	} else {
		imx6q_opp_check_speed_grading(cpu_dev);
		imx6q_opp_check_speed_grading(cpu_dev);
	}


	/* Because we have added the OPPs here, we must free them */
	/* Because we have added the OPPs here, we must free them */
	free_opp = true;
	free_opp = true;