lkml.org 
[lkml]   [2015]   [Apr]   [20]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    /
    Date
    From
    SubjectRe: [PATCH 1/2] cpufreq: mediatek: Add MT8173 cpufreq driver
    On Mon, Apr 20, 2015 at 05:27:26PM +0800, pi-cheng.chen wrote:
    > This patch implements MT8173 specific cpufreq driver with OPP table defined
    > in the driver code.
    >
    > Signed-off-by: pi-cheng.chen <pi-cheng.chen@linaro.org>
    > ---
    > drivers/cpufreq/Kconfig.arm | 6 +
    > drivers/cpufreq/Makefile | 1 +
    > drivers/cpufreq/mt8173-cpufreq.c | 509 +++++++++++++++++++++++++++++++++++++++
    > 3 files changed, 516 insertions(+)
    > create mode 100644 drivers/cpufreq/mt8173-cpufreq.c
    >
    > diff --git a/drivers/cpufreq/Kconfig.arm b/drivers/cpufreq/Kconfig.arm
    > index 1b06fc4..25643c7 100644
    > --- a/drivers/cpufreq/Kconfig.arm
    > +++ b/drivers/cpufreq/Kconfig.arm
    > @@ -132,6 +132,12 @@ config ARM_KIRKWOOD_CPUFREQ
    > This adds the CPUFreq driver for Marvell Kirkwood
    > SoCs.
    >
    > +config ARM_MT8173_CPUFREQ
    > + bool "Mediatek MT8173 CPUFreq support"
    > + depends on ARCH_MEDIATEK && REGULATOR

    I think you want to 'select REGULATOR' here; because REGULATOR isn't
    a user-visible option.

    > + help
    > + This adds the CPUFreq driver support for Mediatek MT8173 SoC.
    > +
    > config ARM_OMAP2PLUS_CPUFREQ
    > bool "TI OMAP2+"
    > depends on ARCH_OMAP2PLUS
    > diff --git a/drivers/cpufreq/Makefile b/drivers/cpufreq/Makefile
    > index 82a1821..da9d616 100644
    > --- a/drivers/cpufreq/Makefile
    > +++ b/drivers/cpufreq/Makefile
    > @@ -62,6 +62,7 @@ obj-$(CONFIG_ARM_HIGHBANK_CPUFREQ) += highbank-cpufreq.o
    > obj-$(CONFIG_ARM_IMX6Q_CPUFREQ) += imx6q-cpufreq.o
    > obj-$(CONFIG_ARM_INTEGRATOR) += integrator-cpufreq.o
    > obj-$(CONFIG_ARM_KIRKWOOD_CPUFREQ) += kirkwood-cpufreq.o
    > +obj-$(CONFIG_ARM_MT8173_CPUFREQ) += mt8173-cpufreq.o
    > obj-$(CONFIG_ARM_OMAP2PLUS_CPUFREQ) += omap-cpufreq.o
    > obj-$(CONFIG_ARM_PXA2xx_CPUFREQ) += pxa2xx-cpufreq.o
    > obj-$(CONFIG_PXA3xx) += pxa3xx-cpufreq.o
    > diff --git a/drivers/cpufreq/mt8173-cpufreq.c b/drivers/cpufreq/mt8173-cpufreq.c
    > new file mode 100644
    > index 0000000..a310e72
    > --- /dev/null
    > +++ b/drivers/cpufreq/mt8173-cpufreq.c
    > @@ -0,0 +1,509 @@
    > +/*
    > +* Copyright (c) 2015 Linaro Ltd.
    > +* Author: Pi-Cheng Chen <pi-cheng.chen@linaro.org>
    > +*
    > +* This program is free software; you can redistribute it and/or modify
    > +* it under the terms of the GNU General Public License version 2 as
    > +* published by the Free Software Foundation.
    > +*
    > +* 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.
    > +*/
    > +
    > +#include <linux/clk.h>
    > +#include <linux/cpu.h>
    > +#include <linux/cpufreq.h>
    > +#include <linux/cpumask.h>
    > +#include <linux/module.h>
    > +#include <linux/of.h>
    > +#include <linux/regulator/consumer.h>
    > +#include <linux/slab.h>
    > +
    > +#define MIN_VOLT_SHIFT 100000
    > +#define MAX_VOLT_SHIFT 200000
    > +
    > +#define OPP(f, vp, vs) { \
    > + .freq = f, \
    > + .vproc = vp, \
    > + .vsram = vs, \
    > + }
    > +
    > +struct mtk_cpu_opp {
    > + unsigned int freq;
    > + int vproc;
    > + int vsram;
    > +};
    > +
    > +/*
    > + * The struct cpu_dvfs_info holds necessary information for doing CPU DVFS of
    > + * each cluster. For Mediatek SoCs, each CPU cluster in SoC has two voltage
    > + * inputs, Vproc and Vsram. For some cluster in SoC, the two voltage inputs are
    > + * supplied by different PMICs. In this case, when scaling up/down the voltage
    > + * of Vsram and Vproc, the two voltage inputs need to be controlled under a
    > + * hardware limitation: 100mV < Vsram - Vproc < 200mV
    > + * When scaling up/down the clock frequency of a cluster, the clock source need
    > + * to be switched to another stable PLL clock temporarily, and switched back to
    > + * the original PLL after the it becomes stable at target frequency.
    > + * Hence the voltage inputs of cluster need to be set to an intermediate voltage
    > + * before the clock frequency being scaled up/down.
    > + */
    > +
    > +struct cpu_dvfs_info {
    > + cpumask_t cpus;
    > +
    > + struct mtk_cpu_opp *opp_tbl;
    > + struct mtk_cpu_opp *intermediate_opp;
    > + int nr_opp;
    > +
    > + struct regulator *proc_reg;
    > + struct regulator *sram_reg;
    > + struct clk *cpu_clk;
    > + struct clk *inter_pll;
    > +};
    > +
    > +/*
    > + * This is a temporary solution until we have new OPPv2 bindings. Therefore we
    > + * could describe the OPPs with (freq, volt, volt) tuple properly in device
    > + * tree.
    > + */
    > +
    > +/* OPP table for LITTLE cores of MT8173 */
    > +struct mtk_cpu_opp mt8173_l_opp[] = {

    static const?

    > + OPP(507000000, 859000, 0),
    > + OPP(702000000, 908000, 0),
    > + OPP(1001000000, 983000, 0),
    > + OPP(1105000000, 1009000, 0),
    > + OPP(1183000000, 1028000, 0),
    > + OPP(1404000000, 1083000, 0),
    > + OPP(1508000000, 1109000, 0),
    > + OPP(1573000000, 1125000, 0),
    > +};
    > +
    > +/* OPP table for big cores of MT8173 */
    > +struct mtk_cpu_opp mt8173_b_opp[] = {

    same here?

    > + OPP(507000000, 828000, 928000),
    > + OPP(702000000, 867000, 967000),
    > + OPP(1001000000, 927000, 1027000),
    > + OPP(1209000000, 968000, 1068000),
    > + OPP(1404000000, 1007000, 1107000),
    > + OPP(1612000000, 1049000, 1149000),
    > + OPP(1807000000, 1089000, 1150000),
    > + OPP(1989000000, 1125000, 1150000),
    > +};
    > +
    [..]
    > +static int mtk_cpufreq_voltage_trace(struct cpu_dvfs_info *info,
    > + struct mtk_cpu_opp *opp)
    > +{
    > + struct regulator *proc_reg = info->proc_reg;
    > + struct regulator *sram_reg = info->sram_reg;
    > + int old_vproc, new_vproc, old_vsram, new_vsram, vsram, vproc, ret;
    > +
    > + old_vproc = regulator_get_voltage(proc_reg);
    > + old_vsram = regulator_get_voltage(sram_reg);
    > +
    > + new_vproc = opp->vproc;
    > + new_vsram = opp->vsram;
    > +
    > + /*
    > + * In the case the voltage is going to be scaled up, Vsram and Vproc
    > + * need to be scaled up step by step. In each step, Vsram needs to be
    > + * set to (Vproc + 200mV) first, then Vproc is set to (Vsram - 100mV).
    > + * Repeat the step until Vsram and Vproc are set to target voltage.
    > + */
    > + if (old_vproc < new_vproc) {
    > +next_up_step:
    > + old_vsram = regulator_get_voltage(sram_reg);
    > +
    > + vsram = (new_vsram - old_vproc < MAX_VOLT_SHIFT) ?
    > + new_vsram : old_vproc + MAX_VOLT_SHIFT;
    > + vsram = get_regulator_voltage_floor(sram_reg, vsram);
    > +
    > + ret = regulator_set_voltage(sram_reg, vsram, vsram);
    > + if (ret)
    > + return ret;
    > +
    > + vproc = (new_vsram == vsram) ?
    > + new_vproc : vsram - MIN_VOLT_SHIFT;
    > + vproc = get_regulator_voltage_ceil(proc_reg, vproc);
    > +
    > + ret = regulator_set_voltage(proc_reg, vproc, vproc);
    > + if (ret) {
    > + regulator_set_voltage(sram_reg, old_vsram, old_vsram);
    > + return ret;
    > + }
    > +
    > + if (new_vproc == vproc && new_vsram == vsram)
    > + return 0;
    > +
    > + old_vproc = vproc;
    > + goto next_up_step;

    Perhaps a naive question: but, is this the correct place to do this? I
    would expect this stepping behavior to be implemented in the driver
    controlling the regulator you are consuming. It seems strange to do it
    here.

    Josh


    \
     
     \ /
      Last update: 2015-04-20 16:41    [W:4.421 / U:0.008 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site