]> asedeno.scripts.mit.edu Git - linux.git/commitdiff
cpufreq: Add imx-cpufreq-dt driver
authorLeonard Crestez <leonard.crestez@nxp.com>
Mon, 13 May 2019 11:01:38 +0000 (11:01 +0000)
committerViresh Kumar <viresh.kumar@linaro.org>
Mon, 20 May 2019 07:17:48 +0000 (12:47 +0530)
Right now in upstream imx8m cpufreq support just lists a common subset
of OPPs because the higher ones should only be attempted after checking
speed grading in fuses.

Add a small driver which checks speed grading from nvmem cells before
registering cpufreq-dt.

This driver allows unlocking all frequencies for imx8mm and imx8mq and
could be applied to other chips like imx7d

Signed-off-by: Leonard Crestez <leonard.crestez@nxp.com>
Signed-off-by: Viresh Kumar <viresh.kumar@linaro.org>
drivers/cpufreq/Kconfig.arm
drivers/cpufreq/Makefile
drivers/cpufreq/cpufreq-dt-platdev.c
drivers/cpufreq/imx-cpufreq-dt.c [new file with mode: 0644]
drivers/soc/imx/soc-imx8.c

index 179a1d302f48d13b0a56bb2b04b5bb72ffa697a8..982efdf9c7e504cee381e824ed60dfdb7440c3cd 100644 (file)
@@ -92,6 +92,15 @@ config ARM_IMX6Q_CPUFREQ
 
          If in doubt, say N.
 
+config ARM_IMX_CPUFREQ_DT
+       tristate "Freescale i.MX8M cpufreq support"
+       depends on ARCH_MXC && CPUFREQ_DT
+       help
+         This adds cpufreq driver support for Freescale i.MX8M series SoCs,
+         based on cpufreq-dt.
+
+         If in doubt, say N.
+
 config ARM_KIRKWOOD_CPUFREQ
        def_bool MACH_KIRKWOOD
        help
index 689b26c6f94957631abb3a90067bf3ecbe7b87e1..7bcda2273d0cc809f3348b949764f7208bac73dd 100644 (file)
@@ -56,6 +56,7 @@ obj-$(CONFIG_ACPI_CPPC_CPUFREQ)               += cppc_cpufreq.o
 obj-$(CONFIG_ARCH_DAVINCI)             += davinci-cpufreq.o
 obj-$(CONFIG_ARM_HIGHBANK_CPUFREQ)     += highbank-cpufreq.o
 obj-$(CONFIG_ARM_IMX6Q_CPUFREQ)                += imx6q-cpufreq.o
+obj-$(CONFIG_ARM_IMX_CPUFREQ_DT)       += imx-cpufreq-dt.o
 obj-$(CONFIG_ARM_KIRKWOOD_CPUFREQ)     += kirkwood-cpufreq.o
 obj-$(CONFIG_ARM_MEDIATEK_CPUFREQ)     += mediatek-cpufreq.o
 obj-$(CONFIG_MACH_MVEBU_V7)            += mvebu-cpufreq.o
index 47729a22c159dfbfde80a47245d40eb83262a9d3..19c1aad57e269ece0aa54ce40d3628c88e9cb562 100644 (file)
@@ -108,6 +108,9 @@ static const struct of_device_id blacklist[] __initconst = {
        { .compatible = "calxeda,highbank", },
        { .compatible = "calxeda,ecx-2000", },
 
+       { .compatible = "fsl,imx8mq", },
+       { .compatible = "fsl,imx8mm", },
+
        { .compatible = "marvell,armadaxp", },
 
        { .compatible = "mediatek,mt2701", },
diff --git a/drivers/cpufreq/imx-cpufreq-dt.c b/drivers/cpufreq/imx-cpufreq-dt.c
new file mode 100644 (file)
index 0000000..e1aa346
--- /dev/null
@@ -0,0 +1,96 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright 2019 NXP
+ */
+
+#include <linux/cpu.h>
+#include <linux/err.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/nvmem-consumer.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/pm_opp.h>
+#include <linux/slab.h>
+
+#define OCOTP_CFG3_SPEED_GRADE_SHIFT   8
+#define OCOTP_CFG3_SPEED_GRADE_MASK    (0x3 << 8)
+#define OCOTP_CFG3_MKT_SEGMENT_SHIFT    6
+#define OCOTP_CFG3_MKT_SEGMENT_MASK     (0x3 << 6)
+
+static const struct of_device_id imx_cpufreq_dt_match_list[] = {
+       { .compatible = "fsl,imx8mm" },
+       { .compatible = "fsl,imx8mq" },
+       {}
+};
+
+/* cpufreq-dt device registered by imx-cpufreq-dt */
+static struct platform_device *cpufreq_dt_pdev;
+static struct opp_table *cpufreq_opp_table;
+
+static int imx_cpufreq_dt_probe(struct platform_device *pdev)
+{
+       struct device *cpu_dev = get_cpu_device(0);
+       struct device_node *np;
+       const struct of_device_id *match;
+       u32 cell_value, supported_hw[2];
+       int speed_grade, mkt_segment;
+       int ret;
+
+       np = of_find_node_by_path("/");
+       match = of_match_node(imx_cpufreq_dt_match_list, np);
+       of_node_put(np);
+       if (!match)
+               return -ENODEV;
+
+       ret = nvmem_cell_read_u32(cpu_dev, "speed_grade", &cell_value);
+       if (ret)
+               return ret;
+
+       speed_grade = (cell_value & OCOTP_CFG3_SPEED_GRADE_MASK) >> OCOTP_CFG3_SPEED_GRADE_SHIFT;
+       mkt_segment = (cell_value & OCOTP_CFG3_MKT_SEGMENT_MASK) >> OCOTP_CFG3_MKT_SEGMENT_SHIFT;
+       supported_hw[0] = BIT(speed_grade);
+       supported_hw[1] = BIT(mkt_segment);
+       dev_info(&pdev->dev, "cpu speed grade %d mkt segment %d supported-hw %#x %#x\n",
+                       speed_grade, mkt_segment, supported_hw[0], supported_hw[1]);
+
+       cpufreq_opp_table = dev_pm_opp_set_supported_hw(cpu_dev, supported_hw, 2);
+       if (IS_ERR(cpufreq_opp_table)) {
+               ret = PTR_ERR(cpufreq_opp_table);
+               dev_err(&pdev->dev, "Failed to set supported opp: %d\n", ret);
+               return ret;
+       }
+
+       cpufreq_dt_pdev = platform_device_register_data(
+                       &pdev->dev, "cpufreq-dt", -1, NULL, 0);
+       if (IS_ERR(cpufreq_dt_pdev)) {
+               dev_pm_opp_put_supported_hw(cpufreq_opp_table);
+               ret = PTR_ERR(cpufreq_dt_pdev);
+               dev_err(&pdev->dev, "Failed to register cpufreq-dt: %d\n", ret);
+               return ret;
+       }
+
+       return 0;
+}
+
+static int imx_cpufreq_dt_remove(struct platform_device *pdev)
+{
+       platform_device_unregister(cpufreq_dt_pdev);
+       dev_pm_opp_put_supported_hw(cpufreq_opp_table);
+
+       return 0;
+}
+
+static struct platform_driver imx_cpufreq_dt_driver = {
+       .probe = imx_cpufreq_dt_probe,
+       .remove = imx_cpufreq_dt_remove,
+       .driver = {
+               .name = "imx-cpufreq-dt",
+       },
+};
+module_platform_driver(imx_cpufreq_dt_driver);
+
+MODULE_ALIAS("platform:imx-cpufreq-dt");
+MODULE_DESCRIPTION("Freescale i.MX cpufreq speed grading driver");
+MODULE_LICENSE("GPL v2");
index fc6429f9170a68530c3698fb2e126e86ff39c8fc..b1bd8e2543ac529b1c581c4617e192bf89bca1a0 100644 (file)
@@ -103,6 +103,9 @@ static int __init imx8_soc_init(void)
        if (IS_ERR(soc_dev))
                goto free_rev;
 
+       if (IS_ENABLED(CONFIG_ARM_IMX_CPUFREQ_DT))
+               platform_device_register_simple("imx-cpufreq-dt", -1, NULL, 0);
+
        return 0;
 
 free_rev: