cpufreq: Add imx-cpufreq-dt driver
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>
This commit is contained in:
parent
a188339ca5
commit
4d28ba1d62
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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", },
|
||||
|
|
|
@ -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");
|
|
@ -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:
|
||||
|
|
Loading…
Reference in New Issue