* Re: [PATCH 12/15] arm64: dts: msm8974: thermal: Add interrupt support
From: Amit Kucheria @ 2019-07-29 9:29 UTC (permalink / raw)
To: Luca Weiss
Cc: Linux Kernel Mailing List, linux-arm-msm, Bjorn Andersson,
Eduardo Valentin, Andy Gross, Andy Gross, Daniel Lezcano,
Mark Rutland, Rob Herring, Zhang Rui, Brian Masney, DTML
In-Reply-To: <2812534.bLfc0ztHNv@g550jk>
On Mon, Jul 29, 2019 at 2:33 PM Luca Weiss <luca@z3ntu.xyz> wrote:
>
> On Freitag, 26. Juli 2019 00:18:47 CEST Amit Kucheria wrote:
> > Register upper-lower interrupt for the tsens controller.
> >
> > Signed-off-by: Amit Kucheria <amit.kucheria@linaro.org>
> > ---
> > Cc: masneyb@onstation.org
> >
> > arch/arm/boot/dts/qcom-msm8974.dtsi | 36 +++++++++++++++--------------
> > 1 file changed, 19 insertions(+), 17 deletions(-)
> >
>
> Hi, the title of this patch should be "arm" and not "arm64".
Good catch! Copy-paste error, will fix.
^ permalink raw reply
* Re: [PATCH v3 0/6] Introduce Bandwidth OPPs for interconnect paths
From: Viresh Kumar @ 2019-07-29 9:24 UTC (permalink / raw)
To: Saravana Kannan
Cc: Georgi Djakov, Rob Herring, Mark Rutland, Viresh Kumar,
Nishanth Menon, Stephen Boyd, Rafael J. Wysocki, Vincent Guittot,
Sweeney, Sean, daidavid1, Rajendra Nayak, Sibi Sankar,
Bjorn Andersson, Evan Green, Android Kernel Team, Linux PM,
open list:OPEN FIRMWARE AND FLATTENED DEVICE TREE BINDINGS, LKML
In-Reply-To: <CAGETcx_-=b3An9YdxLUnZap=0iaeczvWTEnw65FMLU8BwA3HfQ@mail.gmail.com>
On 18-07-19, 21:12, Saravana Kannan wrote:
> On Wed, Jul 17, 2019 at 10:37 PM Viresh Kumar <viresh.kumar@linaro.org> wrote:
> > I would like
> > to put this data in the GPU OPP table only. What about putting a
> > range in the GPU OPP table for the Bandwidth if it can change so much
> > for the same frequency.
>
> I don't think the range is going to work.
Any specific reason for that ?
> If a GPU is doing purely
> computational work, it's not unreasonable for it to vote for the
> lowest bandwidth for any GPU frequency.
I think that is fine, but if the GPU is able to find how much
bandwidth it needs why can't it just pass that value without needing
to have another OPP table for the path ?
The interconnect can then take all the requests and have its own OPP
table to get help on deciding what stable bandwidth to use.
--
viresh
^ permalink raw reply
* Re: [PATCH 6/8] PM / OPP: Support adjusting OPP voltages at runtime
From: Viresh Kumar @ 2019-07-29 9:20 UTC (permalink / raw)
To: Roger Lu
Cc: Stephen Boyd, Andrew-sh Cheng (鄭式勳),
MyungJoo Ham, Kyungmin Park, Chanwoo Choi, Rob Herring,
Mark Rutland, Matthias Brugger, Rafael J. Wysocki, Nishanth Menon,
Stephen Boyd, linux-pm@vger.kernel.org,
devicetree@vger.kernel.org, linux-arm-kernel@lists.infradead.org,
linux-mediatek@lists.infradead.org
In-Reply-To: <1564371555.18434.11.camel@mtksdaap41>
On 29-07-19, 11:39, Roger Lu wrote:
> Dear Stephen Boyd,
>
> This patch is derived from [1]. Please kindly shares the suggestion to
> us. Thanks very much.
>
> [1]: https://lore.kernel.org/patchwork/patch/599279/
>
> Dear Viresh,
>
> I followed _opp_set_availability() coding style to refine
> dev_pm_opp_adjust_voltage() from this patch. Is this refinement suitable
> for OPP core? Thanks a lot.
Looks okay from a quick look.
--
viresh
^ permalink raw reply
* Re: [PATCH v15 2/2] dt-bindings: spi: Document Renesas R-Car Gen3 RPC-IF controller bindings
From: Geert Uytterhoeven @ 2019-07-29 9:15 UTC (permalink / raw)
To: Mason Yang
Cc: Mark Brown, Rob Herring, Mark Rutland, Linux Kernel Mailing List,
linux-spi, Linux-Renesas, Geert Uytterhoeven,
open list:OPEN FIRMWARE AND FLATTENED DEVICE TREE BINDINGS,
juliensu, Simon Horman, Lee Jones, Sergei Shtylyov, Marek Vasut,
Miquel Raynal
In-Reply-To: <1564108975-27423-3-git-send-email-masonccyang@mxic.com.tw>
Hi Mason,
Thanks for the update!
On Fri, Jul 26, 2019 at 4:19 AM Mason Yang <masonccyang@mxic.com.tw> wrote:
> Dcument the bindings used by the Renesas R-Car Gen3 RPC-IF controller.
Document
>
> Signed-off-by: Mason Yang <masonccyang@mxic.com.tw>
> Reviewed-by: Rob Herring <robh@kernel.org>
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/spi/spi-renesas-rpc.txt
> @@ -0,0 +1,46 @@
[...]
> +- flash: should be represented by a subnode of the RPC-IF node,
> + which "compatible" property contains "jedec,spi-nor", it presents
> + SPI is used.
Sorry, I failed to parse the last subsentence.
> +
> +Example:
> +
> + rpc: spi@ee200000 {
> + compatible = "renesas,r8a77995-rpc", "renesas,rcar-gen3-rpc";
> + reg = <0 0xee200000 0 0x200>, <0 0x08000000 0 0x4000000>,
> + <0 0xee208000 0 0x100>;
> + reg-names = "regs", "dirmap", "wbuf";
> + clocks = <&cpg CPG_MOD 917>;
> + clock-names = "rpc";
> + power-domains = <&sysc R8A77995_PD_ALWAYS_ON>;
> + resets = <&cpg 917>;
> + #address-cells = <1>;
> + #size-cells = <0>;
> +
> + flash@0 {
> + compatible = "jedec,spi-nor";
> + reg = <0>;
> + spi-max-frequency = <40000000>;
> + spi-tx-bus-width = <1>;
> + spi-rx-bus-width = <1>;
Shouldn't those <1> be <4>, as this is QSPI?
> + };
> + };
Gr{oetje,eeting}s,
Geert
--
Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- geert@linux-m68k.org
In personal conversations with technical people, I call myself a hacker. But
when I'm talking to journalists I just say "programmer" or something like that.
-- Linus Torvalds
^ permalink raw reply
* RE: [EXT] Re: [Patch v3 1/2] dt-bindings: spi: spi-fsl-qspi: Add ls2080a compatibility string to bindings
From: Ashish Kumar @ 2019-07-29 9:11 UTC (permalink / raw)
To: Rob Herring, Leo Li
Cc: devicetree@vger.kernel.org, bbrezillon@kernel.org, Kuldeep Singh,
broonie@kernel.org, linux-mtd@lists.infradead.org,
linux-arm-kernel@lists.infradead.org
In-Reply-To: <20190709200837.GA7806@bogus>
> -----Original Message-----
> From: Rob Herring <robh@kernel.org>
> Sent: Wednesday, July 10, 2019 1:39 AM
> To: Ashish Kumar <ashish.kumar@nxp.com>
> Cc: devicetree@vger.kernel.org; bbrezillon@kernel.org; broonie@kernel.org;
> linux-arm-kernel@lists.infradead.org; linux-mtd@lists.infradead.org; Ashish
> Kumar <ashish.kumar@nxp.com>; Kuldeep Singh <kuldeep.singh@nxp.com>;
> Ashish Kumar <ashish.kumar@nxp.com>
> Subject: [EXT] Re: [Patch v3 1/2] dt-bindings: spi: spi-fsl-qspi: Add ls2080a
> compatibility string to bindings
>
> Caution: EXT Email
>
> On Wed, 19 Jun 2019 16:41:53 +0530, Ashish Kumar wrote:
> > There are 2 version of QSPI-IP, according to which controller
> > registers sets can be big endian or little endian.There are some other
> > minor changes like RX fifo depth etc.
> >
> > The big endian version uses driver compatible "fsl,ls1021a-qspi" and
> > little endian version uses driver compatible "fsl,ls2080a-qspi"
> >
> > Signed-off-by: Kuldeep Singh <kuldeep.singh@nxp.com>
> > Signed-off-by: Ashish Kumar <ashish.kumar@nxp.com>
> > ---
> > v3:
> > Rebase to top
> > v2:
> > Convert to patch series and rebasing done on top of tree
> >
> > Documentation/devicetree/bindings/spi/spi-fsl-qspi.txt | 3 +--
> > 1 file changed, 1 insertion(+), 2 deletions(-)
> >
>
> Reviewed-by: Rob Herring <robh@kernel.org>
Hi Leo,
I think Rob, is waiting for you ack.
Regards
Ashish
^ permalink raw reply
* RE: [EXT] Re: [Patch v3 2/2] dt-bindings: spi: spi-fsl-qspi: Add bindings of ls1088a and ls1012a
From: Ashish Kumar @ 2019-07-29 9:08 UTC (permalink / raw)
To: Rob Herring, Leo Li
Cc: devicetree@vger.kernel.org, bbrezillon@kernel.org, Kuldeep Singh,
broonie@kernel.org, linux-mtd@lists.infradead.org,
linux-arm-kernel@lists.infradead.org
In-Reply-To: <20190709200857.GA8477@bogus>
> -----Original Message-----
> From: Rob Herring <robh@kernel.org>
> Sent: Wednesday, July 10, 2019 1:39 AM
> To: Ashish Kumar <ashish.kumar@nxp.com>
> Cc: devicetree@vger.kernel.org; bbrezillon@kernel.org; broonie@kernel.org;
> linux-arm-kernel@lists.infradead.org; linux-mtd@lists.infradead.org; Ashish
> Kumar <ashish.kumar@nxp.com>; Kuldeep Singh <kuldeep.singh@nxp.com>;
> Ashish Kumar <ashish.kumar@nxp.com>
> Subject: [EXT] Re: [Patch v3 2/2] dt-bindings: spi: spi-fsl-qspi: Add bindings of
> ls1088a and ls1012a
>
> Caution: EXT Email
>
> On Wed, 19 Jun 2019 16:41:54 +0530, Ashish Kumar wrote:
> > Signed-off-by: Kuldeep Singh <kuldeep.singh@nxp.com>
> > Signed-off-by: Ashish Kumar <ashish.kumar@nxp.com>
> > ---
> > v3:
> > Rebase to top
> > v2:
> > Convert to patch series and rebasing done on top of tree
> >
> > Documentation/devicetree/bindings/spi/spi-fsl-qspi.txt | 2 ++
> > 1 file changed, 2 insertions(+)
> >
>
> Reviewed-by: Rob Herring <robh@kernel.org>
Hi Leo,
I think Rob, is waiting for you ack.
Regards
Ashish
^ permalink raw reply
* Re: [PATCH 00/15] thermal: qcom: tsens: Add interrupt support
From: Brian Masney @ 2019-07-29 9:07 UTC (permalink / raw)
To: Amit Kucheria
Cc: LKML, linux-arm-msm, Bjorn Andersson, Eduardo Valentin,
Andy Gross, Andy Gross, Daniel Lezcano, Mark Rutland, Rob Herring,
Zhang Rui, Marc Gonzalez,
open list:OPEN FIRMWARE AND FLATTENED DEVICE TREE BINDINGS,
Linux PM list
In-Reply-To: <CAHLCerNay31+RNQvQZyxMMVyb1mLLfN5BoZbz-M+bMqbmbYwtA@mail.gmail.com>
On Sat, Jul 27, 2019 at 12:58:54PM +0530, Amit Kucheria wrote:
> On Fri, Jul 26, 2019 at 4:59 PM Brian Masney <masneyb@onstation.org> wrote:
> > On Fri, Jul 26, 2019 at 04:40:16PM +0530, Amit Kucheria wrote:
> > > How well does cpufreq work on 8974? I haven't looked at it yet but
> > > we'll need it for thermal throttling.
> >
> > I'm not sure how to tell if the frequency is dynamically changed during
> > runtime on arm. x86-64 shows this information in /proc/cpuinfo. Here's
> > the /proc/cpuinfo on the Nexus 5:
>
> Nah. /proc/cpuinfo won't show what we need.
>
> Try the following:
>
> $ grep "" /sys/devices/system/cpu/cpufreq/policy?/*
>
> More specifically, the following files have the information you need.
> Run watch -n1 on them.
>
> $ grep "" /sys/devices/system/cpu/cpufreq/policy?/scaling_*_freq
There's no cpufreq directory on msm8974:
# ls -1 /sys/devices/system/cpu/
cpu0
cpu1
cpu2
cpu3
cpuidle
hotplug
isolated
kernel_max
modalias
offline
online
possible
power
present
smt
uevent
I'm using qcom_defconfig.
Brian
^ permalink raw reply
* Re: [PATCH 12/15] arm64: dts: msm8974: thermal: Add interrupt support
From: Luca Weiss @ 2019-07-29 9:03 UTC (permalink / raw)
To: linux-kernel
Cc: Amit Kucheria, linux-arm-msm, bjorn.andersson, edubezval,
andy.gross, Andy Gross, Daniel Lezcano, Mark Rutland, Rob Herring,
Zhang Rui, masneyb, devicetree
In-Reply-To: <ec8205566eb9c015ad51fbb88f0da7ca60b414fd.1564091601.git.amit.kucheria@linaro.org>
[-- Attachment #1: Type: text/plain, Size: 416 bytes --]
On Freitag, 26. Juli 2019 00:18:47 CEST Amit Kucheria wrote:
> Register upper-lower interrupt for the tsens controller.
>
> Signed-off-by: Amit Kucheria <amit.kucheria@linaro.org>
> ---
> Cc: masneyb@onstation.org
>
> arch/arm/boot/dts/qcom-msm8974.dtsi | 36 +++++++++++++++--------------
> 1 file changed, 19 insertions(+), 17 deletions(-)
>
Hi, the title of this patch should be "arm" and not "arm64".
Luca
[-- Attachment #2: This is a digitally signed message part. --]
[-- Type: application/pgp-signature, Size: 833 bytes --]
^ permalink raw reply
* Re: [PATCH v3] arm64: dts: imx8mq: Init rates and parents configs for clocks
From: Daniel Baluta @ 2019-07-29 9:03 UTC (permalink / raw)
To: Guido Günther
Cc: Devicetree List, baruch, Abel Vesa, Anson Huang, Carlo Caione,
Andrey Smirnov, Daniel Baluta, Sascha Hauer,
Angus Ainslie (Purism), Linux Kernel Mailing List, dl-linux-imx,
Fabio Estevam, Shawn Guo, S.j. Wang, linux-arm-kernel,
Lucas Stach
In-Reply-To: <20190729083130.GA3904@bogon.m.sigxcpu.org>
On Mon, Jul 29, 2019 at 11:32 AM Guido Günther <agx@sigxcpu.org> wrote:
>
> Hi,
> On Sun, Jul 28, 2019 at 05:12:18PM +0300, Daniel Baluta wrote:
> > From: Abel Vesa <abel.vesa@nxp.com>
> >
> > Add the initial configuration for clocks that need default parent and rate
> > setting. This is based on the vendor tree clock provider parents and rates
> > configuration except this is doing the setup in dts rather then using clock
> > consumer API in a clock provider driver.
> >
> > Note that by adding the initial rate setting for audio_pll1/audio_pll
> > setting we need to remove it from imx8mq-librem5-devkit.dts
> > imx8mq-librem5-devkit.dts
> >
> > Signed-off-by: Abel Vesa <abel.vesa@nxp.com>
> > Signed-off-by: Daniel Baluta <daniel.baluta@nxp.com>
> > ---
> > Changes since v2:
> > - set rate for audio_pll1/audio_pll2 in the dtsi file and
> > remove the setting from imx8mq-librem5-devkit.dts
> >
> > .../dts/freescale/imx8mq-librem5-devkit.dts | 5 -----
> > arch/arm64/boot/dts/freescale/imx8mq.dtsi | 21 +++++++++++++++++++
> > 2 files changed, 21 insertions(+), 5 deletions(-)
> >
> > diff --git a/arch/arm64/boot/dts/freescale/imx8mq-librem5-devkit.dts b/arch/arm64/boot/dts/freescale/imx8mq-librem5-devkit.dts
> > index 683a11035643..c702ccc82867 100644
> > --- a/arch/arm64/boot/dts/freescale/imx8mq-librem5-devkit.dts
> > +++ b/arch/arm64/boot/dts/freescale/imx8mq-librem5-devkit.dts
> > @@ -169,11 +169,6 @@
> > };
> > };
> >
> > -&clk {
> > - assigned-clocks = <&clk IMX8MQ_AUDIO_PLL1>, <&clk IMX8MQ_AUDIO_PLL2>;
> > - assigned-clock-rates = <786432000>, <722534400>;
> > -};
> > -
> > &dphy {
> > status = "okay";
> > };
> > diff --git a/arch/arm64/boot/dts/freescale/imx8mq.dtsi b/arch/arm64/boot/dts/freescale/imx8mq.dtsi
> > index 02fbd0625318..c67625a881a4 100644
> > --- a/arch/arm64/boot/dts/freescale/imx8mq.dtsi
> > +++ b/arch/arm64/boot/dts/freescale/imx8mq.dtsi
> > @@ -494,6 +494,27 @@
> > clock-names = "ckil", "osc_25m", "osc_27m",
> > "clk_ext1", "clk_ext2",
> > "clk_ext3", "clk_ext4";
> > + assigned-clocks = <&clk IMX8MQ_VIDEO_PLL1>,
> > + <&clk IMX8MQ_AUDIO_PLL1>,
> > + <&clk IMX8MQ_AUDIO_PLL2>,
> > + <&clk IMX8MQ_CLK_AHB>,
> > + <&clk IMX8MQ_CLK_NAND_USDHC_BUS>,
> > + <&clk IMX8MQ_CLK_AUDIO_AHB>,
> > + <&clk IMX8MQ_VIDEO_PLL1_REF_SEL>,
> > + <&clk IMX8MQ_CLK_NOC>;
> > + assigned-clock-parents = <0>,
> > + <0>,
> > + <0>,
> > + <&clk IMX8MQ_SYS1_PLL_133M>,
> > + <&clk IMX8MQ_SYS1_PLL_266M>,
> > + <&clk IMX8MQ_SYS2_PLL_500M>,
> > + <&clk IMX8MQ_CLK_27M>,
> > + <&clk IMX8MQ_SYS1_PLL_800M>;
> > + assigned-clock-rates = <593999999>,
> > + <786432000>,
> > + <722534400>;
> > +
> > +
> > };
> >
> > src: reset-controller@30390000 {
>
> togethe with http://code.bulix.org/pd88jp-812381?raw tested on
> linux-20190725 (plus mipi dsi):
>
> Tested-by: Guido Günther <agx@sigxcpu.org>
Thanks for testing this Guido. Can you please add your Tested-by
to my fourth version of the patch.
[PATCH v4] arm64: dts: imx8mq: Init rates and parents configs for clocks
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply
* RE: [PATCH 4/6] thermal: qoriq: Add clock operations
From: Anson Huang @ 2019-07-29 8:40 UTC (permalink / raw)
To: Guido Günther
Cc: rui.zhang@intel.com, edubezval@gmail.com,
daniel.lezcano@linaro.org, robh+dt@kernel.org,
mark.rutland@arm.com, shawnguo@kernel.org, s.hauer@pengutronix.de,
kernel@pengutronix.de, festevam@gmail.com,
mturquette@baylibre.com, sboyd@kernel.org, l.stach@pengutronix.de,
Abel Vesa, andrew.smirnov@gmail.com, angus@akkea.ca,
ccaione@baylibre.com, Leonard Crestez <leonard.crestez>
In-Reply-To: <20190729081221.GA2523@bogon.m.sigxcpu.org>
Hi, Guido
> On Fri, Jul 05, 2019 at 12:56:10PM +0800, Anson.Huang@nxp.com wrote:
> > From: Anson Huang <Anson.Huang@nxp.com>
> >
> > Some platforms like i.MX8MQ has clock control for this module, need to
> > add clock operations to make sure the driver is working properly.
> >
> > Signed-off-by: Anson Huang <Anson.Huang@nxp.com>
> > ---
> > drivers/thermal/qoriq_thermal.c | 24 ++++++++++++++++++++++++
> > 1 file changed, 24 insertions(+)
> >
> > diff --git a/drivers/thermal/qoriq_thermal.c
> > b/drivers/thermal/qoriq_thermal.c index 2b2f79b..0813c1b 100644
> > --- a/drivers/thermal/qoriq_thermal.c
> > +++ b/drivers/thermal/qoriq_thermal.c
> > @@ -2,6 +2,7 @@
> > //
> > // Copyright 2016 Freescale Semiconductor, Inc.
> >
> > +#include <linux/clk.h>
> > #include <linux/module.h>
> > #include <linux/platform_device.h>
> > #include <linux/err.h>
> > @@ -72,6 +73,7 @@ struct qoriq_sensor {
> >
> > struct qoriq_tmu_data {
> > struct qoriq_tmu_regs __iomem *regs;
> > + struct clk *clk;
> > bool little_endian;
> > struct qoriq_sensor *sensor[SITES_MAX];
> > };
> > @@ -208,6 +210,19 @@ static int qoriq_tmu_probe(struct platform_device
> *pdev)
> > return PTR_ERR(data->regs);
> > }
> >
> > + data->clk = devm_clk_get(&pdev->dev, NULL);
> > + if (IS_ERR(data->clk)) {
> > + if (PTR_ERR(data->clk) == -EPROBE_DEFER)
> > + return -EPROBE_DEFER;
> > + data->clk = NULL;
> > + }
>
> Wouldn't devm_clk_get_optional make more sense?
Yes, looks like it is better, will fix it in V2.
>
> > +
> > + ret = clk_prepare_enable(data->clk);
> > + if (ret) {
> > + dev_err(&pdev->dev, "Failed to enable clock\n");
> > + return ret;
> > + }
> > +
> > qoriq_tmu_init_device(data); /* TMU initialization */
> >
> > ret = qoriq_tmu_calibration(pdev); /* TMU calibration */
> > @@ -235,6 +250,8 @@ static int qoriq_tmu_remove(struct
> platform_device *pdev)
> > /* Disable monitoring */
> > tmu_write(data, TMR_DISABLE, &data->regs->tmr);
> >
> > + clk_disable_unprepare(data->clk);
> > +
> > platform_set_drvdata(pdev, NULL);
> >
> > return 0;
> > @@ -250,14 +267,21 @@ static int __maybe_unused
> qoriq_tmu_suspend(struct device *dev)
> > tmr &= ~TMR_ME;
> > tmu_write(data, tmr, &data->regs->tmr);
> >
> > + clk_disable_unprepare(data->clk);
> > +
> > return 0;
> > }
> >
> > static int __maybe_unused qoriq_tmu_resume(struct device *dev) {
> > u32 tmr;
> > + int ret;
> > struct qoriq_tmu_data *data = dev_get_drvdata(dev);
> >
> > + ret = clk_prepare_enable(data->clk);
> > + if (ret)
> > + return ret;
> > +
> > /* Enable monitoring */
> > tmr = tmu_read(data, &data->regs->tmr);
> > tmr |= TMR_ME;
>
> Apart from that it looks like what Fabio sent and what i tested so
>
> Reviewed-by: Guido Günther <agx@sigxcpu.org>
Thanks,
Anson
>
> Cheers,
> -- Guido
>
> > --
> > 2.7.4
> >
> >
> > _______________________________________________
> > linux-arm-kernel mailing list
> > linux-arm-kernel@lists.infradead.org
> > https://eur01.safelinks.protection.outlook.com/?url=http%3A%2F%2Flists
> > .infradead.org%2Fmailman%2Flistinfo%2Flinux-arm-
> kernel&data=02%7C0
> >
> 1%7Canson.huang%40nxp.com%7C9263c240da82482af57908d713fc7d0b%7
> C686ea1d
> >
> 3bc2b4c6fa92cd99c5c301635%7C0%7C0%7C636999847472894624&sdat
> a=0YAlK
> > V8ZS37vHFz311nOdBP8qBbqisvjFBtaSS1PV9k%3D&reserved=0
> >
^ permalink raw reply
* [PATCH V2 4/4] thermal: qoriq: Add clock operations
From: Anson.Huang @ 2019-07-29 8:39 UTC (permalink / raw)
To: rui.zhang, edubezval, daniel.lezcano, robh+dt, mark.rutland,
linux-pm, devicetree, linux-kernel
Cc: Linux-imx
In-Reply-To: <20190729083915.4855-1-Anson.Huang@nxp.com>
From: Anson Huang <Anson.Huang@nxp.com>
Some platforms like i.MX8MQ has clock control for this module,
need to add clock operations to make sure the driver is working
properly.
Signed-off-by: Anson Huang <Anson.Huang@nxp.com>
Reviewed-by: Guido Günther <agx@sigxcpu.org>
---
Changes since V1:
- use devm_clk_get_optional() instead of devm_clk_get().
---
drivers/thermal/qoriq_thermal.c | 21 +++++++++++++++++++++
1 file changed, 21 insertions(+)
diff --git a/drivers/thermal/qoriq_thermal.c b/drivers/thermal/qoriq_thermal.c
index 2b2f79b..0ae45c0 100644
--- a/drivers/thermal/qoriq_thermal.c
+++ b/drivers/thermal/qoriq_thermal.c
@@ -2,6 +2,7 @@
//
// Copyright 2016 Freescale Semiconductor, Inc.
+#include <linux/clk.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/err.h>
@@ -72,6 +73,7 @@ struct qoriq_sensor {
struct qoriq_tmu_data {
struct qoriq_tmu_regs __iomem *regs;
+ struct clk *clk;
bool little_endian;
struct qoriq_sensor *sensor[SITES_MAX];
};
@@ -208,6 +210,16 @@ static int qoriq_tmu_probe(struct platform_device *pdev)
return PTR_ERR(data->regs);
}
+ data->clk = devm_clk_get_optional(&pdev->dev, NULL);
+ if (IS_ERR(data->clk))
+ return PTR_ERR(data->clk);
+
+ ret = clk_prepare_enable(data->clk);
+ if (ret) {
+ dev_err(&pdev->dev, "Failed to enable clock\n");
+ return ret;
+ }
+
qoriq_tmu_init_device(data); /* TMU initialization */
ret = qoriq_tmu_calibration(pdev); /* TMU calibration */
@@ -235,6 +247,8 @@ static int qoriq_tmu_remove(struct platform_device *pdev)
/* Disable monitoring */
tmu_write(data, TMR_DISABLE, &data->regs->tmr);
+ clk_disable_unprepare(data->clk);
+
platform_set_drvdata(pdev, NULL);
return 0;
@@ -250,14 +264,21 @@ static int __maybe_unused qoriq_tmu_suspend(struct device *dev)
tmr &= ~TMR_ME;
tmu_write(data, tmr, &data->regs->tmr);
+ clk_disable_unprepare(data->clk);
+
return 0;
}
static int __maybe_unused qoriq_tmu_resume(struct device *dev)
{
u32 tmr;
+ int ret;
struct qoriq_tmu_data *data = dev_get_drvdata(dev);
+ ret = clk_prepare_enable(data->clk);
+ if (ret)
+ return ret;
+
/* Enable monitoring */
tmr = tmu_read(data, &data->regs->tmr);
tmr |= TMR_ME;
--
2.7.4
^ permalink raw reply related
* [PATCH V2 3/4] dt-bindings: thermal: qoriq: Add optional clocks property
From: Anson.Huang @ 2019-07-29 8:39 UTC (permalink / raw)
To: rui.zhang, edubezval, daniel.lezcano, robh+dt, mark.rutland,
linux-pm, devicetree, linux-kernel
Cc: Linux-imx
In-Reply-To: <20190729083915.4855-1-Anson.Huang@nxp.com>
From: Anson Huang <Anson.Huang@nxp.com>
Some platforms have clock control for TMU, add optional
clocks property to the binding doc.
Signed-off-by: Anson Huang <Anson.Huang@nxp.com>
---
No changes.
---
Documentation/devicetree/bindings/thermal/qoriq-thermal.txt | 1 +
1 file changed, 1 insertion(+)
diff --git a/Documentation/devicetree/bindings/thermal/qoriq-thermal.txt b/Documentation/devicetree/bindings/thermal/qoriq-thermal.txt
index 04cbb90..28f2cba 100644
--- a/Documentation/devicetree/bindings/thermal/qoriq-thermal.txt
+++ b/Documentation/devicetree/bindings/thermal/qoriq-thermal.txt
@@ -23,6 +23,7 @@ Required properties:
Optional property:
- little-endian : If present, the TMU registers are little endian. If absent,
the default is big endian.
+- clocks : the clock for clocking the TMU silicon.
Example:
--
2.7.4
^ permalink raw reply related
* [PATCH V2 2/4] thermal: qoriq: Use __maybe_unused instead of #if CONFIG_PM_SLEEP
From: Anson.Huang @ 2019-07-29 8:39 UTC (permalink / raw)
To: rui.zhang, edubezval, daniel.lezcano, robh+dt, mark.rutland,
linux-pm, devicetree, linux-kernel
Cc: Linux-imx
In-Reply-To: <20190729083915.4855-1-Anson.Huang@nxp.com>
From: Anson Huang <Anson.Huang@nxp.com>
Use __maybe_unused for power management related functions
instead of #if CONFIG_PM_SLEEP to simply the code.
Signed-off-by: Anson Huang <Anson.Huang@nxp.com>
---
No changes.
---
drivers/thermal/qoriq_thermal.c | 6 ++----
1 file changed, 2 insertions(+), 4 deletions(-)
diff --git a/drivers/thermal/qoriq_thermal.c b/drivers/thermal/qoriq_thermal.c
index c7c7de2..2b2f79b 100644
--- a/drivers/thermal/qoriq_thermal.c
+++ b/drivers/thermal/qoriq_thermal.c
@@ -240,8 +240,7 @@ static int qoriq_tmu_remove(struct platform_device *pdev)
return 0;
}
-#ifdef CONFIG_PM_SLEEP
-static int qoriq_tmu_suspend(struct device *dev)
+static int __maybe_unused qoriq_tmu_suspend(struct device *dev)
{
u32 tmr;
struct qoriq_tmu_data *data = dev_get_drvdata(dev);
@@ -254,7 +253,7 @@ static int qoriq_tmu_suspend(struct device *dev)
return 0;
}
-static int qoriq_tmu_resume(struct device *dev)
+static int __maybe_unused qoriq_tmu_resume(struct device *dev)
{
u32 tmr;
struct qoriq_tmu_data *data = dev_get_drvdata(dev);
@@ -266,7 +265,6 @@ static int qoriq_tmu_resume(struct device *dev)
return 0;
}
-#endif
static SIMPLE_DEV_PM_OPS(qoriq_tmu_pm_ops,
qoriq_tmu_suspend, qoriq_tmu_resume);
--
2.7.4
^ permalink raw reply related
* [PATCH V2 1/4] thermal: qoriq: Use devm_platform_ioremap_resource() instead of of_iomap()
From: Anson.Huang @ 2019-07-29 8:39 UTC (permalink / raw)
To: rui.zhang, edubezval, daniel.lezcano, robh+dt, mark.rutland,
linux-pm, devicetree, linux-kernel
Cc: Linux-imx
From: Anson Huang <Anson.Huang@nxp.com>
Use devm_platform_ioremap_resource() instead of of_iomap() to
save the iounmap() call in error handle path;
Signed-off-by: Anson Huang <Anson.Huang@nxp.com>
---
No changes.
---
drivers/thermal/qoriq_thermal.c | 18 ++++++------------
1 file changed, 6 insertions(+), 12 deletions(-)
diff --git a/drivers/thermal/qoriq_thermal.c b/drivers/thermal/qoriq_thermal.c
index 7b36493..c7c7de2 100644
--- a/drivers/thermal/qoriq_thermal.c
+++ b/drivers/thermal/qoriq_thermal.c
@@ -202,32 +202,27 @@ static int qoriq_tmu_probe(struct platform_device *pdev)
data->little_endian = of_property_read_bool(np, "little-endian");
- data->regs = of_iomap(np, 0);
- if (!data->regs) {
+ data->regs = devm_platform_ioremap_resource(pdev, 0);
+ if (IS_ERR(data->regs)) {
dev_err(&pdev->dev, "Failed to get memory region\n");
- ret = -ENODEV;
- goto err_iomap;
+ return PTR_ERR(data->regs);
}
qoriq_tmu_init_device(data); /* TMU initialization */
ret = qoriq_tmu_calibration(pdev); /* TMU calibration */
if (ret < 0)
- goto err_tmu;
+ goto err;
ret = qoriq_tmu_register_tmu_zone(pdev);
if (ret < 0) {
dev_err(&pdev->dev, "Failed to register sensors\n");
- ret = -ENODEV;
- goto err_iomap;
+ goto err;
}
return 0;
-err_tmu:
- iounmap(data->regs);
-
-err_iomap:
+err:
platform_set_drvdata(pdev, NULL);
return ret;
@@ -240,7 +235,6 @@ static int qoriq_tmu_remove(struct platform_device *pdev)
/* Disable monitoring */
tmu_write(data, TMR_DISABLE, &data->regs->tmr);
- iounmap(data->regs);
platform_set_drvdata(pdev, NULL);
return 0;
--
2.7.4
^ permalink raw reply related
* Re: [PATCH] dt-bindings: rcar-imr: Rename bindings documentation file
From: Geert Uytterhoeven @ 2019-07-29 8:31 UTC (permalink / raw)
To: Simon Horman
Cc: Mauro Carvalho Chehab, Rob Herring, Mark Rutland, Magnus Damm,
Geert Uytterhoeven, Linux Media Mailing List,
open list:OPEN FIRMWARE AND FLATTENED DEVICE TREE BINDINGS,
Linux-Renesas, Niklas Söderlund
In-Reply-To: <20190729074757.9581-1-horms+renesas@verge.net.au>
On Mon, Jul 29, 2019 at 9:48 AM Simon Horman <horms+renesas@verge.net.au> wrote:
> Renesas media binding documentation files uses a naming schema of
use
> 'renesas,<module>.txt'. Rename IMR file to match this pattern.
the IMR file?
>
> Cc: Niklas Söderlund <niklas.soderlund+renesas@ragnatech.se>
> Signed-off-by: Simon Horman <horms+renesas@verge.net.au>
Reviewed-by: Geert Uytterhoeven <geert+renesas@glider.be>
Gr{oetje,eeting}s,
Geert
--
Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- geert@linux-m68k.org
In personal conversations with technical people, I call myself a hacker. But
when I'm talking to journalists I just say "programmer" or something like that.
-- Linus Torvalds
^ permalink raw reply
* Re: [PATCH v3] arm64: dts: imx8mq: Init rates and parents configs for clocks
From: Guido Günther @ 2019-07-29 8:31 UTC (permalink / raw)
To: Daniel Baluta
Cc: shawnguo, s.hauer, festevam, linux-imx, l.stach, ccaione,
abel.vesa, baruch, andrew.smirnov, devicetree, linux-arm-kernel,
linux-kernel, shengjiu.wang, angus, Anson.Huang
In-Reply-To: <20190728141218.12702-1-daniel.baluta@nxp.com>
Hi,
On Sun, Jul 28, 2019 at 05:12:18PM +0300, Daniel Baluta wrote:
> From: Abel Vesa <abel.vesa@nxp.com>
>
> Add the initial configuration for clocks that need default parent and rate
> setting. This is based on the vendor tree clock provider parents and rates
> configuration except this is doing the setup in dts rather then using clock
> consumer API in a clock provider driver.
>
> Note that by adding the initial rate setting for audio_pll1/audio_pll
> setting we need to remove it from imx8mq-librem5-devkit.dts
> imx8mq-librem5-devkit.dts
>
> Signed-off-by: Abel Vesa <abel.vesa@nxp.com>
> Signed-off-by: Daniel Baluta <daniel.baluta@nxp.com>
> ---
> Changes since v2:
> - set rate for audio_pll1/audio_pll2 in the dtsi file and
> remove the setting from imx8mq-librem5-devkit.dts
>
> .../dts/freescale/imx8mq-librem5-devkit.dts | 5 -----
> arch/arm64/boot/dts/freescale/imx8mq.dtsi | 21 +++++++++++++++++++
> 2 files changed, 21 insertions(+), 5 deletions(-)
>
> diff --git a/arch/arm64/boot/dts/freescale/imx8mq-librem5-devkit.dts b/arch/arm64/boot/dts/freescale/imx8mq-librem5-devkit.dts
> index 683a11035643..c702ccc82867 100644
> --- a/arch/arm64/boot/dts/freescale/imx8mq-librem5-devkit.dts
> +++ b/arch/arm64/boot/dts/freescale/imx8mq-librem5-devkit.dts
> @@ -169,11 +169,6 @@
> };
> };
>
> -&clk {
> - assigned-clocks = <&clk IMX8MQ_AUDIO_PLL1>, <&clk IMX8MQ_AUDIO_PLL2>;
> - assigned-clock-rates = <786432000>, <722534400>;
> -};
> -
> &dphy {
> status = "okay";
> };
> diff --git a/arch/arm64/boot/dts/freescale/imx8mq.dtsi b/arch/arm64/boot/dts/freescale/imx8mq.dtsi
> index 02fbd0625318..c67625a881a4 100644
> --- a/arch/arm64/boot/dts/freescale/imx8mq.dtsi
> +++ b/arch/arm64/boot/dts/freescale/imx8mq.dtsi
> @@ -494,6 +494,27 @@
> clock-names = "ckil", "osc_25m", "osc_27m",
> "clk_ext1", "clk_ext2",
> "clk_ext3", "clk_ext4";
> + assigned-clocks = <&clk IMX8MQ_VIDEO_PLL1>,
> + <&clk IMX8MQ_AUDIO_PLL1>,
> + <&clk IMX8MQ_AUDIO_PLL2>,
> + <&clk IMX8MQ_CLK_AHB>,
> + <&clk IMX8MQ_CLK_NAND_USDHC_BUS>,
> + <&clk IMX8MQ_CLK_AUDIO_AHB>,
> + <&clk IMX8MQ_VIDEO_PLL1_REF_SEL>,
> + <&clk IMX8MQ_CLK_NOC>;
> + assigned-clock-parents = <0>,
> + <0>,
> + <0>,
> + <&clk IMX8MQ_SYS1_PLL_133M>,
> + <&clk IMX8MQ_SYS1_PLL_266M>,
> + <&clk IMX8MQ_SYS2_PLL_500M>,
> + <&clk IMX8MQ_CLK_27M>,
> + <&clk IMX8MQ_SYS1_PLL_800M>;
> + assigned-clock-rates = <593999999>,
> + <786432000>,
> + <722534400>;
> +
> +
> };
>
> src: reset-controller@30390000 {
togethe with http://code.bulix.org/pd88jp-812381?raw tested on
linux-20190725 (plus mipi dsi):
Tested-by: Guido Günther <agx@sigxcpu.org>
Cheers,
-- Guido
> --
> 2.17.1
>
^ permalink raw reply
* DT yaml bindings: handling of complicated compatible property
From: Bartosz Golaszewski @ 2019-07-29 8:31 UTC (permalink / raw)
To: Rob Herring, Frank Rowand; +Cc: devicetree
Hello,
I decided to attempt to convert the DT binding for AT24 EEPROM driver
to yaml and am not sure on how to handle the compatible property with
a lot of options.
In at24 we support 23 models and 8 vendors (184 vendor,model
combinations) plus 5 exceptions (with model names not following the
general convention).
Do I simply use the oneOf specifier and list all possible options? Or
is there a better approach.
Best regards,
Bartosz Golaszewski
^ permalink raw reply
* RE: [PATCH v2 2/2] dt-bindings: usb: renesas_gen3: Rename bindings documentation file
From: Yoshihiro Shimoda @ 2019-07-29 8:25 UTC (permalink / raw)
To: Simon Horman
Cc: Greg Kroah-Hartman, Geert Uytterhoeven, Kuninori Morimoto,
Magnus Damm, USB list, Linux-Renesas, Rob Herring, Mark Rutland,
open list:OPEN FIRMWARE AND FLATTENED DEVICE TREE BINDINGS <devicetree@vger.kernel.org>, Niklas Söderlund
In-Reply-To: <20190729081440.ftgchumfoszlht4q@verge.net.au>
Hi Simon-san,
> From: Simon Horman, Sent: Monday, July 29, 2019 5:15 PM
<snip>
> > > > > Unfortunately the previous version has already made it into usb-next
> > > > > 23c46801d14cb647 dt-bindings: usb: renesas_gen3: Rename bindings
> > > > > documentation file
> > > >
> > > > Ok, I guess we should go with that version.
> > >
> > > So can you resend this series based on 5.3-rc1 so I know what to apply?
> >
> > Since your usb-testing branch already has it which is merged from Felipe's usb-next branch,
> > I don't think Simon has to resend this series.
> >
> > https://www.spinics.net/lists/linux-usb/msg182103.html
>
> Thanks and sorry for the confusion.
>
> In v5.2-rc1 we had:
>
> devicetree/bindings/usb/renesas_usb3.txt
> devicetree/bindings/usb/renesas_usbhs.txt
>
>
> In v5.3-rc1 we have:
>
> devicetree/bindings/usb/renesas,usb3.txt
> devicetree/bindings/usb/renesas,usbhs.txt
>
> Which reflects v1 of this patchset. And I think this is an improvement.
>
> Shimoda-san, can you let me know if you would like me to rebase v2
> on v5.3-rc1? That would would give us:
>
> devicetree/bindings/usb/renesas,usb3-peri.txt
> devicetree/bindings/usb/renesas,usbhs.txt [unchanged]
Thank you for the detail. I would like you to rebase v2 like that, if possible.
Best regards,
Yoshihiro Shimoda
^ permalink raw reply
* [PATCH v4 2/2] PM / AVS: SVS: Introduce SVS engine
From: Roger Lu @ 2019-07-29 8:20 UTC (permalink / raw)
To: Kevin Hilman, Rob Herring, Nicolas Boichat, Stephen Boyd
Cc: Fan Chen, HenryC Chen, yt.lee, Angus Lin, Mark Rutland,
Matthias Brugger, Nishanth Menon, Roger Lu, devicetree,
linux-arm-kernel, linux-mediatek, linux-kernel, linux-pm
In-Reply-To: <20190729082032.13661-1-roger.lu@mediatek.com>
The SVS (Smart Voltage Scaling) engine is a piece of hardware which is
used to calculate optimized voltage values of several power domains, e.g.
CPU/GPU/CCI, according to chip process corner, temperatures, and other
factors. Then DVFS driver could apply those optimized voltage values to
reduce power consumption.
Signed-off-by: Roger Lu <roger.lu@mediatek.com>
---
drivers/power/avs/Kconfig | 10 +
drivers/power/avs/Makefile | 1 +
drivers/power/avs/mtk_svs.c | 2075 +++++++++++++++++++++++++++++++++
include/linux/power/mtk_svs.h | 23 +
4 files changed, 2109 insertions(+)
create mode 100644 drivers/power/avs/mtk_svs.c
create mode 100644 include/linux/power/mtk_svs.h
diff --git a/drivers/power/avs/Kconfig b/drivers/power/avs/Kconfig
index b5a217b828dc..7c72504d5593 100644
--- a/drivers/power/avs/Kconfig
+++ b/drivers/power/avs/Kconfig
@@ -19,3 +19,13 @@ config ROCKCHIP_IODOMAIN
Say y here to enable support io domains on Rockchip SoCs. It is
necessary for the io domain setting of the SoC to match the
voltage supplied by the regulators.
+
+config MTK_SVS
+ bool "MediaTek Smart Voltage Scaling(SVS)"
+ depends on POWER_AVS && MTK_EFUSE
+ help
+ The SVS engine is a piece of hardware which is used to calculate
+ optimized voltage values of several power domains, e.g.
+ CPU clusters/GPU/CCI, according to chip process corner, temperatures,
+ and other factors. Then DVFS driver could apply those optimized voltage
+ values to reduce power consumption.
diff --git a/drivers/power/avs/Makefile b/drivers/power/avs/Makefile
index a1b8cd453f19..57246b977a93 100644
--- a/drivers/power/avs/Makefile
+++ b/drivers/power/avs/Makefile
@@ -1,3 +1,4 @@
# SPDX-License-Identifier: GPL-2.0-only
obj-$(CONFIG_POWER_AVS_OMAP) += smartreflex.o
obj-$(CONFIG_ROCKCHIP_IODOMAIN) += rockchip-io-domain.o
+obj-$(CONFIG_MTK_SVS) += mtk_svs.o
diff --git a/drivers/power/avs/mtk_svs.c b/drivers/power/avs/mtk_svs.c
new file mode 100644
index 000000000000..78ec93c3a4a5
--- /dev/null
+++ b/drivers/power/avs/mtk_svs.c
@@ -0,0 +1,2075 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2018 MediaTek Inc.
+ */
+
+#define pr_fmt(fmt) "[mtk_svs] " fmt
+
+#include <linux/clk.h>
+#include <linux/completion.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/kthread.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/nvmem-consumer.h>
+#include <linux/of_address.h>
+#include <linux/of_irq.h>
+#include <linux/platform_device.h>
+#include <linux/pm_domain.h>
+#include <linux/pm_opp.h>
+#include <linux/pm_qos.h>
+#include <linux/pm_runtime.h>
+#include <linux/power/mtk_svs.h>
+#include <linux/proc_fs.h>
+#include <linux/regulator/consumer.h>
+#include <linux/seq_file.h>
+#include <linux/spinlock.h>
+#include <linux/thermal.h>
+#include <linux/uaccess.h>
+
+#define SVS_INIT01_VOLT_IGNORE 1
+#define SVS_INIT01_VOLT_INC_ONLY 2
+
+#define SVS_PHASE_INIT01 0
+#define SVS_PHASE_INIT02 1
+#define SVS_PHASE_MON 2
+#define SVS_PHASE_ERROR 3
+
+#define SVS_CPU_LITTLE 1
+#define SVS_CPU_BIG 2
+#define SVS_CCI 3
+#define SVS_GPU 4
+
+#define proc_fops_rw(name) \
+ static int name ## _proc_open(struct inode *inode, \
+ struct file *file) \
+ { \
+ return single_open(file, name ## _proc_show, \
+ PDE_DATA(inode)); \
+ } \
+ static const struct file_operations name ## _proc_fops = { \
+ .owner = THIS_MODULE, \
+ .open = name ## _proc_open, \
+ .read = seq_read, \
+ .llseek = seq_lseek, \
+ .release = single_release, \
+ .write = name ## _proc_write, \
+ }
+
+#define proc_fops_ro(name) \
+ static int name ## _proc_open(struct inode *inode, \
+ struct file *file) \
+ { \
+ return single_open(file, name ## _proc_show, \
+ PDE_DATA(inode)); \
+ } \
+ static const struct file_operations name ## _proc_fops = { \
+ .owner = THIS_MODULE, \
+ .open = name ## _proc_open, \
+ .read = seq_read, \
+ .llseek = seq_lseek, \
+ .release = single_release, \
+ }
+
+#define proc_entry(name) {__stringify(name), &name ## _proc_fops}
+
+static DEFINE_SPINLOCK(mtk_svs_lock);
+struct mtk_svs;
+
+enum reg_index {
+ TEMPMONCTL0 = 0,
+ TEMPMONCTL1,
+ TEMPMONCTL2,
+ TEMPMONINT,
+ TEMPMONINTSTS,
+ TEMPMONIDET0,
+ TEMPMONIDET1,
+ TEMPMONIDET2,
+ TEMPH2NTHRE,
+ TEMPHTHRE,
+ TEMPCTHRE,
+ TEMPOFFSETH,
+ TEMPOFFSETL,
+ TEMPMSRCTL0,
+ TEMPMSRCTL1,
+ TEMPAHBPOLL,
+ TEMPAHBTO,
+ TEMPADCPNP0,
+ TEMPADCPNP1,
+ TEMPADCPNP2,
+ TEMPADCMUX,
+ TEMPADCEXT,
+ TEMPADCEXT1,
+ TEMPADCEN,
+ TEMPPNPMUXADDR,
+ TEMPADCMUXADDR,
+ TEMPADCEXTADDR,
+ TEMPADCEXT1ADDR,
+ TEMPADCENADDR,
+ TEMPADCVALIDADDR,
+ TEMPADCVOLTADDR,
+ TEMPRDCTRL,
+ TEMPADCVALIDMASK,
+ TEMPADCVOLTAGESHIFT,
+ TEMPADCWRITECTRL,
+ TEMPMSR0,
+ TEMPMSR1,
+ TEMPMSR2,
+ TEMPADCHADDR,
+ TEMPIMMD0,
+ TEMPIMMD1,
+ TEMPIMMD2,
+ TEMPMONIDET3,
+ TEMPADCPNP3,
+ TEMPMSR3,
+ TEMPIMMD3,
+ TEMPPROTCTL,
+ TEMPPROTTA,
+ TEMPPROTTB,
+ TEMPPROTTC,
+ TEMPSPARE0,
+ TEMPSPARE1,
+ TEMPSPARE2,
+ TEMPSPARE3,
+ TEMPMSR0_1,
+ TEMPMSR1_1,
+ TEMPMSR2_1,
+ TEMPMSR3_1,
+ DESCHAR,
+ TEMPCHAR,
+ DETCHAR,
+ AGECHAR,
+ DCCONFIG,
+ AGECONFIG,
+ FREQPCT30,
+ FREQPCT74,
+ LIMITVALS,
+ VBOOT,
+ DETWINDOW,
+ CONFIG,
+ TSCALCS,
+ RUNCONFIG,
+ SVSEN,
+ INIT2VALS,
+ DCVALUES,
+ AGEVALUES,
+ VOP30,
+ VOP74,
+ TEMP,
+ INTSTS,
+ INTSTSRAW,
+ INTEN,
+ CHKINT,
+ CHKSHIFT,
+ STATUS,
+ VDESIGN30,
+ VDESIGN74,
+ DVT30,
+ DVT74,
+ AGECOUNT,
+ SMSTATE0,
+ SMSTATE1,
+ CTL0,
+ DESDETSEC,
+ TEMPAGESEC,
+ CTRLSPARE0,
+ CTRLSPARE1,
+ CTRLSPARE2,
+ CTRLSPARE3,
+ CORESEL,
+ THERMINTST,
+ INTST,
+ THSTAGE0ST,
+ THSTAGE1ST,
+ THSTAGE2ST,
+ THAHBST0,
+ THAHBST1,
+ SPARE0,
+ SPARE1,
+ SPARE2,
+ SPARE3,
+ THSLPEVEB,
+ reg_num,
+};
+
+static const u32 svs_regs_v2[] = {
+ [TEMPMONCTL0] = 0x000,
+ [TEMPMONCTL1] = 0x004,
+ [TEMPMONCTL2] = 0x008,
+ [TEMPMONINT] = 0x00c,
+ [TEMPMONINTSTS] = 0x010,
+ [TEMPMONIDET0] = 0x014,
+ [TEMPMONIDET1] = 0x018,
+ [TEMPMONIDET2] = 0x01c,
+ [TEMPH2NTHRE] = 0x024,
+ [TEMPHTHRE] = 0x028,
+ [TEMPCTHRE] = 0x02c,
+ [TEMPOFFSETH] = 0x030,
+ [TEMPOFFSETL] = 0x034,
+ [TEMPMSRCTL0] = 0x038,
+ [TEMPMSRCTL1] = 0x03c,
+ [TEMPAHBPOLL] = 0x040,
+ [TEMPAHBTO] = 0x044,
+ [TEMPADCPNP0] = 0x048,
+ [TEMPADCPNP1] = 0x04c,
+ [TEMPADCPNP2] = 0x050,
+ [TEMPADCMUX] = 0x054,
+ [TEMPADCEXT] = 0x058,
+ [TEMPADCEXT1] = 0x05c,
+ [TEMPADCEN] = 0x060,
+ [TEMPPNPMUXADDR] = 0x064,
+ [TEMPADCMUXADDR] = 0x068,
+ [TEMPADCEXTADDR] = 0x06c,
+ [TEMPADCEXT1ADDR] = 0x070,
+ [TEMPADCENADDR] = 0x074,
+ [TEMPADCVALIDADDR] = 0x078,
+ [TEMPADCVOLTADDR] = 0x07c,
+ [TEMPRDCTRL] = 0x080,
+ [TEMPADCVALIDMASK] = 0x084,
+ [TEMPADCVOLTAGESHIFT] = 0x088,
+ [TEMPADCWRITECTRL] = 0x08c,
+ [TEMPMSR0] = 0x090,
+ [TEMPMSR1] = 0x094,
+ [TEMPMSR2] = 0x098,
+ [TEMPADCHADDR] = 0x09c,
+ [TEMPIMMD0] = 0x0a0,
+ [TEMPIMMD1] = 0x0a4,
+ [TEMPIMMD2] = 0x0a8,
+ [TEMPMONIDET3] = 0x0b0,
+ [TEMPADCPNP3] = 0x0b4,
+ [TEMPMSR3] = 0x0b8,
+ [TEMPIMMD3] = 0x0bc,
+ [TEMPPROTCTL] = 0x0c0,
+ [TEMPPROTTA] = 0x0c4,
+ [TEMPPROTTB] = 0x0c8,
+ [TEMPPROTTC] = 0x0cc,
+ [TEMPSPARE0] = 0x0f0,
+ [TEMPSPARE1] = 0x0f4,
+ [TEMPSPARE2] = 0x0f8,
+ [TEMPSPARE3] = 0x0fc,
+ [TEMPMSR0_1] = 0x190,
+ [TEMPMSR1_1] = 0x194,
+ [TEMPMSR2_1] = 0x198,
+ [TEMPMSR3_1] = 0x1b8,
+ [DESCHAR] = 0xc00,
+ [TEMPCHAR] = 0xc04,
+ [DETCHAR] = 0xc08,
+ [AGECHAR] = 0xc0c,
+ [DCCONFIG] = 0xc10,
+ [AGECONFIG] = 0xc14,
+ [FREQPCT30] = 0xc18,
+ [FREQPCT74] = 0xc1c,
+ [LIMITVALS] = 0xc20,
+ [VBOOT] = 0xc24,
+ [DETWINDOW] = 0xc28,
+ [CONFIG] = 0xc2c,
+ [TSCALCS] = 0xc30,
+ [RUNCONFIG] = 0xc34,
+ [SVSEN] = 0xc38,
+ [INIT2VALS] = 0xc3c,
+ [DCVALUES] = 0xc40,
+ [AGEVALUES] = 0xc44,
+ [VOP30] = 0xc48,
+ [VOP74] = 0xc4c,
+ [TEMP] = 0xc50,
+ [INTSTS] = 0xc54,
+ [INTSTSRAW] = 0xc58,
+ [INTEN] = 0xc5c,
+ [CHKINT] = 0xc60,
+ [CHKSHIFT] = 0xc64,
+ [STATUS] = 0xc68,
+ [VDESIGN30] = 0xc6c,
+ [VDESIGN74] = 0xc70,
+ [DVT30] = 0xc74,
+ [DVT74] = 0xc78,
+ [AGECOUNT] = 0xc7c,
+ [SMSTATE0] = 0xc80,
+ [SMSTATE1] = 0xc84,
+ [CTL0] = 0xc88,
+ [DESDETSEC] = 0xce0,
+ [TEMPAGESEC] = 0xce4,
+ [CTRLSPARE0] = 0xcf0,
+ [CTRLSPARE1] = 0xcf4,
+ [CTRLSPARE2] = 0xcf8,
+ [CTRLSPARE3] = 0xcfc,
+ [CORESEL] = 0xf00,
+ [THERMINTST] = 0xf04,
+ [INTST] = 0xf08,
+ [THSTAGE0ST] = 0xf0c,
+ [THSTAGE1ST] = 0xf10,
+ [THSTAGE2ST] = 0xf14,
+ [THAHBST0] = 0xf18,
+ [THAHBST1] = 0xf1c,
+ [SPARE0] = 0xf20,
+ [SPARE1] = 0xf24,
+ [SPARE2] = 0xf28,
+ [SPARE3] = 0xf2c,
+ [THSLPEVEB] = 0xf30,
+};
+
+struct thermal_parameter {
+ int adc_ge_t;
+ int adc_oe_t;
+ int ge;
+ int oe;
+ int gain;
+ int o_vtsabb;
+ int o_vtsmcu1;
+ int o_vtsmcu2;
+ int o_vtsmcu3;
+ int o_vtsmcu4;
+ int o_vtsmcu5;
+ int degc_cali;
+ int adc_cali_en_t;
+ int o_slope;
+ int o_slope_sign;
+ int ts_id;
+};
+
+struct svs_bank_ops {
+ void (*set_freqs_pct)(struct mtk_svs *svs);
+ void (*get_vops)(struct mtk_svs *svs);
+};
+
+struct svs_bank {
+ struct svs_bank_ops *ops;
+ struct completion init_completion;
+ struct device *dev;
+ struct regulator *buck;
+ struct mutex lock; /* lock to protect update voltage process */
+ bool suspended;
+ bool mtcmos_request;
+ bool init01_support;
+ bool init02_support;
+ bool mon_mode_support;
+ s32 volt_offset;
+ u32 *opp_freqs;
+ u32 *freqs_pct;
+ u32 *opp_volts;
+ u32 *init02_volts;
+ u32 *volts;
+ u32 reg_data[3][reg_num];
+ u32 freq_base;
+ u32 vboot;
+ u32 volt_step;
+ u32 volt_base;
+ u32 init01_volt_flag;
+ u32 phase;
+ u32 vmax;
+ u32 vmin;
+ u32 bts;
+ u32 mts;
+ u32 bdes;
+ u32 mdes;
+ u32 mtdes;
+ u32 dcbdet;
+ u32 dcmdet;
+ u32 dthi;
+ u32 dtlo;
+ u32 det_window;
+ u32 det_max;
+ u32 age_config;
+ u32 age_voffset_in;
+ u32 agem;
+ u32 dc_config;
+ u32 dc_voffset_in;
+ u32 dvt_fixed;
+ u32 vco;
+ u32 chkshift;
+ u32 svs_temp;
+ u32 upper_temp_bound;
+ u32 lower_temp_bound;
+ u32 low_temp_threashold;
+ u32 low_temp_offset;
+ u32 coresel;
+ u32 opp_count;
+ u32 intst;
+ u32 systemclk_en;
+ u32 sw_id;
+ u32 hw_id;
+ u32 ctl0;
+ u8 *of_compatible;
+ u8 *name;
+ u8 *zone_name;
+ u8 *buck_name;
+};
+
+struct svs_platform {
+ struct svs_bank *banks;
+ int (*efuse_parsing)(struct mtk_svs *svs);
+ bool fake_efuse;
+ const u32 *regs;
+ u32 bank_num;
+ u32 efuse_num;
+ u32 efuse_check;
+ u32 thermal_efuse_num;
+ u8 *name;
+};
+
+struct mtk_svs {
+ const struct svs_platform *platform;
+ struct svs_bank *bank;
+ struct device *dev;
+ void __iomem *base;
+ struct clk *main_clk;
+ u32 *efuse;
+ u32 *thermal_efuse;
+};
+
+unsigned long claim_mtk_svs_lock(void)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&mtk_svs_lock, flags);
+
+ return flags;
+}
+EXPORT_SYMBOL_GPL(claim_mtk_svs_lock);
+
+void release_mtk_svs_lock(unsigned long flags)
+{
+ spin_unlock_irqrestore(&mtk_svs_lock, flags);
+}
+EXPORT_SYMBOL_GPL(release_mtk_svs_lock);
+
+static u32 percent(u32 numerator, u32 denominator)
+{
+ u32 percent;
+
+ /* If not divide 1000, "numerator * 100" would be data overflow. */
+ numerator /= 1000;
+ denominator /= 1000;
+ percent = ((numerator * 100) + denominator - 1) / denominator;
+
+ return percent;
+}
+
+static u32 svs_readl(struct mtk_svs *svs, enum reg_index i)
+{
+ return readl(svs->base + svs->platform->regs[i]);
+}
+
+static void svs_writel(struct mtk_svs *svs, u32 val, enum reg_index i)
+{
+ writel(val, svs->base + svs->platform->regs[i]);
+}
+
+static void svs_switch_bank(struct mtk_svs *svs)
+{
+ struct svs_bank *svsb = svs->bank;
+
+ svs_writel(svs, svsb->coresel, CORESEL);
+}
+
+static u32 svs_volt_to_opp_volt(u32 svsb_volt,
+ u32 svsb_volt_step, u32 svsb_volt_base)
+{
+ u32 u_volt;
+
+ u_volt = (svsb_volt * svsb_volt_step) + svsb_volt_base;
+
+ return u_volt;
+}
+
+static int svs_get_zone_temperature(struct svs_bank *svsb, int *zone_temp)
+{
+ struct thermal_zone_device *tzd;
+ int ret;
+
+ tzd = thermal_zone_get_zone_by_name(svsb->zone_name);
+ ret = thermal_zone_get_temp(tzd, zone_temp);
+
+ return ret;
+}
+
+static int svs_set_volts(struct svs_bank *svsb, bool force_update)
+{
+ u32 i, svsb_volt, opp_volt, low_temp_offset = 0;
+ int zone_temp, ret;
+
+ mutex_lock(&svsb->lock);
+
+ /* If bank is suspended, it means init02 voltage is applied.
+ * Don't need to update opp voltage anymore.
+ */
+ if (svsb->suspended && !force_update) {
+ pr_notice("%s: bank is suspended\n", svsb->name);
+ mutex_unlock(&svsb->lock);
+ return -EPERM;
+ }
+
+ /* get thermal effect */
+ if (svsb->phase == SVS_PHASE_MON) {
+ if (svsb->svs_temp > svsb->upper_temp_bound &&
+ svsb->svs_temp < svsb->lower_temp_bound) {
+ pr_err("%s: svs_temp is abnormal (0x%x)?\n",
+ svsb->name, svsb->svs_temp);
+ mutex_unlock(&svsb->lock);
+ return -EINVAL;
+ }
+
+ ret = svs_get_zone_temperature(svsb, &zone_temp);
+ if (ret) {
+ pr_err("%s: cannot get zone \"%s\" temperature\n",
+ svsb->name, svsb->zone_name);
+ pr_err("%s: add low_temp_offset = %u\n",
+ svsb->name, svsb->low_temp_offset);
+ zone_temp = svsb->low_temp_threashold;
+ }
+
+ if (zone_temp <= svsb->low_temp_threashold)
+ low_temp_offset = svsb->low_temp_offset;
+ }
+
+ /* vmin <= svsb_volt (opp_volt) <= signed-off voltage */
+ for (i = 0; i < svsb->opp_count; i++) {
+ if (svsb->phase == SVS_PHASE_MON) {
+ svsb_volt = max((svsb->volts[i] + svsb->volt_offset +
+ low_temp_offset), svsb->vmin);
+ opp_volt = svs_volt_to_opp_volt(svsb_volt,
+ svsb->volt_step,
+ svsb->volt_base);
+ } else if (svsb->phase == SVS_PHASE_INIT02) {
+ svsb_volt = max((svsb->init02_volts[i] +
+ svsb->volt_offset), svsb->vmin);
+ opp_volt = svs_volt_to_opp_volt(svsb_volt,
+ svsb->volt_step,
+ svsb->volt_base);
+ } else if (svsb->phase == SVS_PHASE_ERROR) {
+ opp_volt = svsb->opp_volts[i];
+ } else {
+ pr_err("%s: unknown phase: %u?\n",
+ svsb->name, svsb->phase);
+ mutex_unlock(&svsb->lock);
+ return -EINVAL;
+ }
+
+ opp_volt = min(opp_volt, svsb->opp_volts[i]);
+ ret = dev_pm_opp_adjust_voltage(svsb->dev, svsb->opp_freqs[i],
+ opp_volt);
+ if (ret) {
+ pr_err("%s: set voltage failed: %d\n", svsb->name, ret);
+ mutex_unlock(&svsb->lock);
+ return ret;
+ }
+ }
+
+ mutex_unlock(&svsb->lock);
+
+ return 0;
+}
+
+static u32 interpolate(u32 f0, u32 f1, u32 v0, u32 v1, u32 fx)
+{
+ u32 vy;
+
+ if (v0 == v1 || f0 == f1)
+ return v0;
+
+ /* *100 to have decimal fraction factor, +99 for rounding up. */
+ vy = (v0 * 100) - ((((v0 - v1) * 100) / (f0 - f1)) * (f0 - fx));
+ vy = (vy + 99) / 100;
+
+ return vy;
+}
+
+static void svs_get_vops_v2(struct mtk_svs *svs)
+{
+ struct svs_bank *svsb = svs->bank;
+ u32 temp, i;
+
+ temp = svs_readl(svs, VOP30);
+ svsb->volts[6] = (temp >> 24) & 0xff;
+ svsb->volts[4] = (temp >> 16) & 0xff;
+ svsb->volts[2] = (temp >> 8) & 0xff;
+ svsb->volts[0] = (temp & 0xff);
+
+ temp = svs_readl(svs, VOP74);
+ svsb->volts[14] = (temp >> 24) & 0xff;
+ svsb->volts[12] = (temp >> 16) & 0xff;
+ svsb->volts[10] = (temp >> 8) & 0xff;
+ svsb->volts[8] = (temp & 0xff);
+
+ for (i = 0; i <= 7; i++) {
+ if (i < 7) {
+ svsb->volts[(i * 2) + 1] =
+ interpolate(svsb->freqs_pct[i * 2],
+ svsb->freqs_pct[(i + 1) * 2],
+ svsb->volts[i * 2],
+ svsb->volts[(i + 1) * 2],
+ svsb->freqs_pct[(i * 2) + 1]);
+ } else if (i == 7) {
+ svsb->volts[(i * 2) + 1] =
+ interpolate(svsb->freqs_pct[(i - 1) * 2],
+ svsb->freqs_pct[i * 2],
+ svsb->volts[(i - 1) * 2],
+ svsb->volts[i * 2],
+ svsb->freqs_pct[(i * 2) + 1]);
+ }
+ }
+}
+
+static void svs_set_freqs_pct_v2(struct mtk_svs *svs)
+{
+ struct svs_bank *svsb = svs->bank;
+
+ svs_writel(svs,
+ ((svsb->freqs_pct[6] << 24) & 0xff000000) |
+ ((svsb->freqs_pct[4] << 16) & 0xff0000) |
+ ((svsb->freqs_pct[2] << 8) & 0xff00) |
+ (svsb->freqs_pct[0] & 0xff),
+ FREQPCT30);
+ svs_writel(svs,
+ ((svsb->freqs_pct[14] << 24) & 0xff000000) |
+ ((svsb->freqs_pct[12] << 16) & 0xff0000) |
+ ((svsb->freqs_pct[10] << 8) & 0xff00) |
+ ((svsb->freqs_pct[8]) & 0xff),
+ FREQPCT74);
+}
+
+static void svs_set_phase(struct mtk_svs *svs, u32 target_phase)
+{
+ struct svs_bank *svsb = svs->bank;
+ u32 des_char, temp_char, det_char, limit_vals;
+ u32 init2vals, ts_calcs, val, filter, i;
+
+ svs_switch_bank(svs);
+
+ des_char = ((svsb->bdes << 8) & 0xff00) | (svsb->mdes & 0xff);
+ svs_writel(svs, des_char, DESCHAR);
+
+ temp_char = ((svsb->vco << 16) & 0xff0000) |
+ ((svsb->mtdes << 8) & 0xff00) |
+ (svsb->dvt_fixed & 0xff);
+ svs_writel(svs, temp_char, TEMPCHAR);
+
+ det_char = ((svsb->dcbdet << 8) & 0xff00) | (svsb->dcmdet & 0xff);
+ svs_writel(svs, det_char, DETCHAR);
+
+ svs_writel(svs, svsb->dc_config, DCCONFIG);
+ svs_writel(svs, svsb->age_config, AGECONFIG);
+
+ if (svsb->agem == 0x0) {
+ svs_writel(svs, 0x80000000, RUNCONFIG);
+ } else {
+ val = 0x0;
+
+ for (i = 0; i < 24; i += 2) {
+ filter = 0x3 << i;
+
+ if ((svsb->age_config & filter) == 0x0)
+ val |= (0x1 << i);
+ else
+ val |= (svsb->age_config & filter);
+ }
+ svs_writel(svs, val, RUNCONFIG);
+ }
+
+ svsb->ops->set_freqs_pct(svs);
+
+ limit_vals = ((svsb->vmax << 24) & 0xff000000) |
+ ((svsb->vmin << 16) & 0xff0000) |
+ ((svsb->dthi << 8) & 0xff00) |
+ (svsb->dtlo & 0xff);
+ svs_writel(svs, limit_vals, LIMITVALS);
+ svs_writel(svs, (svsb->vboot & 0xff), VBOOT);
+ svs_writel(svs, (svsb->det_window & 0xffff), DETWINDOW);
+ svs_writel(svs, (svsb->det_max & 0xffff), CONFIG);
+
+ if (svsb->chkshift != 0)
+ svs_writel(svs, (svsb->chkshift & 0xff), CHKSHIFT);
+
+ if (svsb->ctl0 != 0)
+ svs_writel(svs, svsb->ctl0, CTL0);
+
+ svs_writel(svs, 0x00ffffff, INTSTS);
+
+ switch (target_phase) {
+ case SVS_PHASE_INIT01:
+ svs_writel(svs, 0x00005f01, INTEN);
+ svs_writel(svs, 0x00000001, SVSEN);
+ break;
+ case SVS_PHASE_INIT02:
+ svs_writel(svs, 0x00005f01, INTEN);
+ init2vals = ((svsb->age_voffset_in << 16) & 0xffff0000) |
+ (svsb->dc_voffset_in & 0xffff);
+ svs_writel(svs, init2vals, INIT2VALS);
+ svs_writel(svs, 0x00000005, SVSEN);
+ break;
+ case SVS_PHASE_MON:
+ ts_calcs = ((svsb->bts << 12) & 0xfff000) | (svsb->mts & 0xfff);
+ svs_writel(svs, ts_calcs, TSCALCS);
+ svs_writel(svs, 0x00FF0000, INTEN);
+ svs_writel(svs, 0x00000002, SVSEN);
+ break;
+ default:
+ WARN_ON(1);
+ break;
+ }
+}
+
+static inline void svs_init01_isr_handler(struct mtk_svs *svs)
+{
+ struct svs_bank *svsb = svs->bank;
+ enum reg_index rg_i;
+
+ pr_notice("%s: %s: VDN74:0x%08x, VDN30:0x%08x, DCVALUES:0x%08x\n",
+ svsb->name, __func__, svs_readl(svs, VDESIGN74),
+ svs_readl(svs, VDESIGN30), svs_readl(svs, DCVALUES));
+
+ for (rg_i = TEMPMONCTL0; rg_i < reg_num; rg_i++)
+ svsb->reg_data[SVS_PHASE_INIT01][rg_i] = svs_readl(svs, rg_i);
+
+ svsb->dc_voffset_in = ~(svs_readl(svs, DCVALUES) & 0xffff) + 1;
+ if (svsb->init01_volt_flag == SVS_INIT01_VOLT_IGNORE)
+ svsb->dc_voffset_in = 0;
+ else if ((svsb->dc_voffset_in & 0x8000) &&
+ (svsb->init01_volt_flag == SVS_INIT01_VOLT_INC_ONLY))
+ svsb->dc_voffset_in = 0;
+
+ svsb->age_voffset_in = svs_readl(svs, AGEVALUES) & 0xffff;
+
+ svs_writel(svs, 0x0, SVSEN);
+ svs_writel(svs, 0x1, INTSTS);
+
+ /* svs init01 clock gating */
+ svsb->coresel &= ~svsb->systemclk_en;
+
+ svsb->phase = SVS_PHASE_INIT01;
+ complete(&svsb->init_completion);
+}
+
+static inline void svs_init02_isr_handler(struct mtk_svs *svs)
+{
+ struct svs_bank *svsb = svs->bank;
+ enum reg_index rg_i;
+
+ pr_notice("%s: %s: VOP74:0x%08x, VOP30:0x%08x, DCVALUES:0x%08x\n",
+ svsb->name, __func__, svs_readl(svs, VOP74),
+ svs_readl(svs, VOP30), svs_readl(svs, DCVALUES));
+
+ for (rg_i = TEMPMONCTL0; rg_i < reg_num; rg_i++)
+ svsb->reg_data[SVS_PHASE_INIT02][rg_i] = svs_readl(svs, rg_i);
+
+ svsb->ops->get_vops(svs);
+ memcpy(svsb->init02_volts, svsb->volts, 4 * svsb->opp_count);
+ svsb->phase = SVS_PHASE_INIT02;
+
+ svs_writel(svs, 0x0, SVSEN);
+ svs_writel(svs, 0x1, INTSTS);
+
+ complete(&svsb->init_completion);
+}
+
+static inline void svs_mon_mode_isr_handler(struct mtk_svs *svs)
+{
+ struct svs_bank *svsb = svs->bank;
+ enum reg_index rg_i;
+
+ for (rg_i = TEMPMONCTL0; rg_i < reg_num; rg_i++)
+ svsb->reg_data[SVS_PHASE_MON][rg_i] = svs_readl(svs, rg_i);
+
+ svsb->svs_temp = svs_readl(svs, TEMP) & 0xff;
+
+ svsb->ops->get_vops(svs);
+ svsb->phase = SVS_PHASE_MON;
+
+ svs_writel(svs, 0x00ff0000, INTSTS);
+}
+
+static inline void svs_error_isr_handler(struct mtk_svs *svs)
+{
+ const struct svs_platform *svsp = svs->platform;
+ struct svs_bank *svsb = svs->bank;
+ enum reg_index rg_i;
+
+ pr_err("%s(): %s(%s)", __func__, svsp->name, svsb->name);
+ pr_err("CORESEL(0x%x) = 0x%08x\n",
+ svsp->regs[CORESEL], svs_readl(svs, CORESEL)),
+ pr_err("SVSEN(0x%x) = 0x%08x, INTSTS(0x%x) = 0x%08x\n",
+ svsp->regs[SVSEN], svs_readl(svs, SVSEN),
+ svsp->regs[INTSTS], svs_readl(svs, INTSTS));
+ pr_err("SMSTATE0(0x%x) = 0x%08x, SMSTATE1(0x%x) = 0x%08x\n",
+ svsp->regs[SMSTATE0], svs_readl(svs, SMSTATE0),
+ svsp->regs[SMSTATE1], svs_readl(svs, SMSTATE1));
+
+ for (rg_i = TEMPMONCTL0; rg_i < reg_num; rg_i++)
+ svsb->reg_data[SVS_PHASE_MON][rg_i] = svs_readl(svs, rg_i);
+
+ svsb->init01_support = false;
+ svsb->init02_support = false;
+ svsb->mon_mode_support = false;
+
+ if (svsb->phase == SVS_PHASE_MON)
+ svsb->phase = SVS_PHASE_INIT02;
+
+ svs_writel(svs, 0x0, SVSEN);
+ svs_writel(svs, 0x00ffffff, INTSTS);
+}
+
+static inline void svs_isr_handler(struct mtk_svs *svs)
+{
+ u32 intsts, svsen;
+
+ svs_switch_bank(svs);
+
+ intsts = svs_readl(svs, INTSTS);
+ svsen = svs_readl(svs, SVSEN);
+
+ if (intsts == 0x1 && ((svsen & 0x7) == 0x1))
+ svs_init01_isr_handler(svs);
+ else if ((intsts == 0x1) && ((svsen & 0x7) == 0x5))
+ svs_init02_isr_handler(svs);
+ else if ((intsts & 0x00ff0000) != 0x0)
+ svs_mon_mode_isr_handler(svs);
+ else
+ svs_error_isr_handler(svs);
+}
+
+static irqreturn_t svs_isr(int irq, void *data)
+{
+ struct mtk_svs *svs = (struct mtk_svs *)data;
+ const struct svs_platform *svsp = svs->platform;
+ struct svs_bank *svsb = NULL;
+ unsigned long flags;
+ u32 idx;
+
+ flags = claim_mtk_svs_lock();
+ for (idx = 0; idx < svsp->bank_num; idx++) {
+ svsb = &svsp->banks[idx];
+ svs->bank = svsb;
+
+ if (svsb->suspended)
+ continue;
+ else if (svsb->intst & svs_readl(svs, INTST))
+ continue;
+
+ svs_isr_handler(svs);
+ break;
+ }
+ release_mtk_svs_lock(flags);
+
+ if (svsb->phase != SVS_PHASE_INIT01)
+ svs_set_volts(svsb, false);
+
+ return IRQ_HANDLED;
+}
+
+static void svs_mon_mode(struct mtk_svs *svs)
+{
+ const struct svs_platform *svsp = svs->platform;
+ struct svs_bank *svsb;
+ unsigned long flags;
+ u32 idx;
+
+ flags = claim_mtk_svs_lock();
+ for (idx = 0; idx < svsp->bank_num; idx++) {
+ svsb = &svsp->banks[idx];
+ svs->bank = svsb;
+
+ if (!svsb->mon_mode_support)
+ continue;
+
+ svs_set_phase(svs, SVS_PHASE_MON);
+ }
+ release_mtk_svs_lock(flags);
+}
+
+static int svs_init02(struct mtk_svs *svs)
+{
+ const struct svs_platform *svsp = svs->platform;
+ struct svs_bank *svsb;
+ unsigned long flags, time_left;
+ u32 idx;
+
+ for (idx = 0; idx < svsp->bank_num; idx++) {
+ svsb = &svsp->banks[idx];
+ svs->bank = svsb;
+
+ if (!svsb->init02_support)
+ continue;
+
+ reinit_completion(&svsb->init_completion);
+ flags = claim_mtk_svs_lock();
+ svs_set_phase(svs, SVS_PHASE_INIT02);
+ release_mtk_svs_lock(flags);
+ time_left =
+ wait_for_completion_timeout(&svsb->init_completion,
+ msecs_to_jiffies(2000));
+ if (time_left == 0) {
+ pr_err("%s: init02 completion timeout\n", svsb->name);
+ return -EBUSY;
+ }
+ }
+
+ return 0;
+}
+
+static int svs_init01(struct mtk_svs *svs)
+{
+ const struct svs_platform *svsp = svs->platform;
+ struct svs_bank *svsb;
+ struct pm_qos_request qos_request = { {0} };
+ unsigned long flags, time_left;
+ bool search_done;
+ int ret = -EINVAL;
+ u32 opp_freqs, opp_vboot, buck_volt, idx, i;
+
+ /* Let CPUs leave idle-off state for initializing svs_init01. */
+ pm_qos_add_request(&qos_request, PM_QOS_CPU_DMA_LATENCY, 0);
+
+ /* Sometimes two svs_bank use the same buck.
+ * Therefore, we set each svs_bank to vboot voltage first.
+ */
+ for (idx = 0; idx < svsp->bank_num; idx++) {
+ svsb = &svsp->banks[idx];
+ search_done = false;
+
+ if (!svsb->init01_support)
+ continue;
+
+ ret = regulator_set_mode(svsb->buck, REGULATOR_MODE_FAST);
+ if (ret)
+ pr_notice("%s: fail to set fast mode: %d\n",
+ svsb->name, ret);
+
+ if (svsb->mtcmos_request) {
+ ret = regulator_enable(svsb->buck);
+ if (ret) {
+ pr_err("%s: fail to enable %s power: %d\n",
+ svsb->name, svsb->buck_name, ret);
+ goto init01_finish;
+ }
+
+ ret = dev_pm_domain_attach(svsb->dev, false);
+ if (ret) {
+ pr_err("%s: attach pm domain fail: %d\n",
+ svsb->name, ret);
+ goto init01_finish;
+ }
+
+ pm_runtime_enable(svsb->dev);
+ ret = pm_runtime_get_sync(svsb->dev);
+ if (ret < 0) {
+ pr_err("%s: turn mtcmos on fail: %d\n",
+ svsb->name, ret);
+ goto init01_finish;
+ }
+ }
+
+ /* Find the fastest freq that can be run at vboot and
+ * fix to that freq until svs_init01 is done.
+ */
+ opp_vboot = svs_volt_to_opp_volt(svsb->vboot,
+ svsb->volt_step,
+ svsb->volt_base);
+
+ for (i = 0; i < svsb->opp_count; i++) {
+ opp_freqs = svsb->opp_freqs[i];
+ if (!search_done && svsb->opp_volts[i] <= opp_vboot) {
+ ret = dev_pm_opp_adjust_voltage(svsb->dev,
+ opp_freqs,
+ opp_vboot);
+ if (ret) {
+ pr_err("%s: set voltage failed: %d\n",
+ svsb->name, ret);
+ goto init01_finish;
+ }
+
+ search_done = true;
+ } else {
+ dev_pm_opp_disable(svsb->dev,
+ svsb->opp_freqs[i]);
+ }
+ }
+ }
+
+ for (idx = 0; idx < svsp->bank_num; idx++) {
+ svsb = &svsp->banks[idx];
+ svs->bank = svsb;
+
+ if (!svsb->init01_support)
+ continue;
+
+ opp_vboot = svs_volt_to_opp_volt(svsb->vboot,
+ svsb->volt_step,
+ svsb->volt_base);
+
+ buck_volt = regulator_get_voltage(svsb->buck);
+ if (buck_volt != opp_vboot) {
+ pr_err("%s: buck voltage: %u, expected vboot: %u\n",
+ svsb->name, buck_volt, opp_vboot);
+ ret = -EPERM;
+ goto init01_finish;
+ }
+
+ init_completion(&svsb->init_completion);
+ flags = claim_mtk_svs_lock();
+ svs_set_phase(svs, SVS_PHASE_INIT01);
+ release_mtk_svs_lock(flags);
+ time_left =
+ wait_for_completion_timeout(&svsb->init_completion,
+ msecs_to_jiffies(2000));
+ if (time_left == 0) {
+ pr_err("%s: init01 completion timeout\n", svsb->name);
+ ret = -EBUSY;
+ goto init01_finish;
+ }
+ }
+
+init01_finish:
+ for (idx = 0; idx < svsp->bank_num; idx++) {
+ svsb = &svsp->banks[idx];
+
+ if (!svsb->init01_support)
+ continue;
+
+ for (i = 0; i < svsb->opp_count; i++)
+ dev_pm_opp_enable(svsb->dev, svsb->opp_freqs[i]);
+
+ if (regulator_set_mode(svsb->buck, REGULATOR_MODE_NORMAL))
+ pr_notice("%s: fail to set normal mode: %d\n",
+ svsb->name, ret);
+
+ if (svsb->mtcmos_request) {
+ if (pm_runtime_put_sync(svsb->dev))
+ pr_err("%s: turn mtcmos off fail: %d\n",
+ svsb->name, ret);
+ pm_runtime_disable(svsb->dev);
+ dev_pm_domain_detach(svsb->dev, 0);
+ if (regulator_disable(svsb->buck))
+ pr_err("%s: fail to disable %s power: %d\n",
+ svsb->name, svsb->buck_name, ret);
+ }
+ }
+
+ pm_qos_remove_request(&qos_request);
+
+ return ret;
+}
+
+static int svs_start(struct mtk_svs *svs)
+{
+ int ret;
+
+ ret = svs_init01(svs);
+ if (ret)
+ return ret;
+
+ ret = svs_init02(svs);
+ if (ret)
+ return ret;
+
+ svs_mon_mode(svs);
+
+ return ret;
+}
+
+static int svs_mt8183_efuse_parsing(struct mtk_svs *svs)
+{
+ const struct svs_platform *svsp = svs->platform;
+ struct thermal_parameter tp;
+ struct svs_bank *svsb;
+ bool mon_mode_support = true;
+ int format[6], x_roomt[6], tb_roomt;
+ u32 idx, i, ft_pgm, mts, temp0, temp1, temp2;
+
+ if (svsp->fake_efuse) {
+ pr_notice("fake efuse\n");
+ svs->efuse[0] = 0x00310080;
+ svs->efuse[1] = 0xabfbf757;
+ svs->efuse[2] = 0x47c747c7;
+ svs->efuse[3] = 0xabfbf757;
+ svs->efuse[4] = 0xe7fca0ec;
+ svs->efuse[5] = 0x47bf4b88;
+ svs->efuse[6] = 0xabfb8fa5;
+ svs->efuse[7] = 0xabfb217b;
+ svs->efuse[8] = 0x4bf34be1;
+ svs->efuse[9] = 0xabfb670d;
+ svs->efuse[16] = 0xabfbc653;
+ svs->efuse[17] = 0x47f347e1;
+ svs->efuse[18] = 0xabfbd848;
+
+ svs->thermal_efuse[0] = 0x02873f69;
+ svs->thermal_efuse[1] = 0xa11d9142;
+ svs->thermal_efuse[2] = 0xa2526900;
+ }
+
+ /* svs efuse parsing */
+ ft_pgm = (svs->efuse[0] >> 4) & 0xf;
+
+ for (idx = 0; idx < svsp->bank_num; idx++) {
+ svsb = &svsp->banks[idx];
+ if (ft_pgm <= 1)
+ svsb->init01_volt_flag = SVS_INIT01_VOLT_IGNORE;
+
+ switch (svsb->sw_id) {
+ case SVS_CPU_LITTLE:
+ svsb->bdes = svs->efuse[16] & 0xff;
+ svsb->mdes = (svs->efuse[16] >> 8) & 0xff;
+ svsb->dcbdet = (svs->efuse[16] >> 16) & 0xff;
+ svsb->dcmdet = (svs->efuse[16] >> 24) & 0xff;
+ svsb->mtdes = (svs->efuse[17] >> 16) & 0xff;
+
+ if (ft_pgm <= 3)
+ svsb->volt_offset += 10;
+ else
+ svsb->volt_offset += 2;
+ break;
+ case SVS_CPU_BIG:
+ svsb->bdes = svs->efuse[18] & 0xff;
+ svsb->mdes = (svs->efuse[18] >> 8) & 0xff;
+ svsb->dcbdet = (svs->efuse[18] >> 16) & 0xff;
+ svsb->dcmdet = (svs->efuse[18] >> 24) & 0xff;
+ svsb->mtdes = svs->efuse[17] & 0xff;
+
+ if (ft_pgm <= 3)
+ svsb->volt_offset += 15;
+ else
+ svsb->volt_offset += 12;
+ break;
+ case SVS_CCI:
+ svsb->bdes = svs->efuse[4] & 0xff;
+ svsb->mdes = (svs->efuse[4] >> 8) & 0xff;
+ svsb->dcbdet = (svs->efuse[4] >> 16) & 0xff;
+ svsb->dcmdet = (svs->efuse[4] >> 24) & 0xff;
+ svsb->mtdes = (svs->efuse[5] >> 16) & 0xff;
+
+ if (ft_pgm <= 3)
+ svsb->volt_offset += 10;
+ else
+ svsb->volt_offset += 2;
+ break;
+ case SVS_GPU:
+ svsb->bdes = svs->efuse[6] & 0xff;
+ svsb->mdes = (svs->efuse[6] >> 8) & 0xff;
+ svsb->dcbdet = (svs->efuse[6] >> 16) & 0xff;
+ svsb->dcmdet = (svs->efuse[6] >> 24) & 0xff;
+ svsb->mtdes = svs->efuse[5] & 0xff;
+
+ if (ft_pgm >= 2) {
+ svsb->freq_base = 800000000; /* 800MHz */
+ svsb->dvt_fixed = 2;
+ }
+ break;
+ default:
+ break;
+ }
+ }
+
+ for (i = 0; i < svsp->efuse_num; i++) {
+ if (svs->efuse[i])
+ pr_notice("M_HW_RES%d: 0x%08x\n", i, svs->efuse[i]);
+ }
+
+ /* thermal efuse parsing */
+ if (!svs->thermal_efuse)
+ return 0;
+
+ tp.adc_ge_t = (svs->thermal_efuse[1] >> 22) & 0x3ff;
+ tp.adc_oe_t = (svs->thermal_efuse[1] >> 12) & 0x3ff;
+
+ tp.o_vtsmcu1 = (svs->thermal_efuse[0] >> 17) & 0x1ff;
+ tp.o_vtsmcu2 = (svs->thermal_efuse[0] >> 8) & 0x1ff;
+ tp.o_vtsmcu3 = svs->thermal_efuse[1] & 0x1ff;
+ tp.o_vtsmcu4 = (svs->thermal_efuse[2] >> 23) & 0x1ff;
+ tp.o_vtsmcu5 = (svs->thermal_efuse[2] >> 5) & 0x1ff;
+ tp.o_vtsabb = (svs->thermal_efuse[2] >> 14) & 0x1ff;
+
+ tp.degc_cali = (svs->thermal_efuse[0] >> 1) & 0x3f;
+ tp.adc_cali_en_t = svs->thermal_efuse[0] & BIT(0);
+ tp.o_slope_sign = (svs->thermal_efuse[0] >> 7) & BIT(0);
+
+ tp.ts_id = (svs->thermal_efuse[1] >> 9) & BIT(0);
+ tp.o_slope = (svs->thermal_efuse[0] >> 26) & 0x3f;
+
+ if (tp.adc_cali_en_t == 1) {
+ if (tp.ts_id == 0)
+ tp.o_slope = 0;
+
+ if ((tp.adc_ge_t < 265 || tp.adc_ge_t > 758) ||
+ (tp.adc_oe_t < 265 || tp.adc_oe_t > 758) ||
+ (tp.o_vtsmcu1 < -8 || tp.o_vtsmcu1 > 484) ||
+ (tp.o_vtsmcu2 < -8 || tp.o_vtsmcu2 > 484) ||
+ (tp.o_vtsmcu3 < -8 || tp.o_vtsmcu3 > 484) ||
+ (tp.o_vtsmcu4 < -8 || tp.o_vtsmcu4 > 484) ||
+ (tp.o_vtsmcu5 < -8 || tp.o_vtsmcu5 > 484) ||
+ (tp.o_vtsabb < -8 || tp.o_vtsabb > 484) ||
+ (tp.degc_cali < 1 || tp.degc_cali > 63)) {
+ pr_err("bad thermal efuse data. disable mon mode\n");
+ mon_mode_support = false;
+ }
+ } else {
+ pr_err("no thermal efuse data. disable mon mode\n");
+ mon_mode_support = false;
+ }
+
+ if (!mon_mode_support) {
+ for (i = 0; i < svsp->thermal_efuse_num; i++)
+ pr_err("thermal_efuse[%u] = 0x%08x\n",
+ i, svs->thermal_efuse[i]);
+
+ for (idx = 0; idx < svsp->bank_num; idx++) {
+ svsb = &svsp->banks[idx];
+ svsb->mon_mode_support = false;
+ }
+
+ return 0;
+ }
+
+ tp.ge = ((tp.adc_ge_t - 512) * 10000) / 4096;
+ tp.oe = (tp.adc_oe_t - 512);
+ tp.gain = (10000 + tp.ge);
+
+ format[0] = (tp.o_vtsmcu1 + 3350 - tp.oe);
+ format[1] = (tp.o_vtsmcu2 + 3350 - tp.oe);
+ format[2] = (tp.o_vtsmcu3 + 3350 - tp.oe);
+ format[3] = (tp.o_vtsmcu4 + 3350 - tp.oe);
+ format[4] = (tp.o_vtsmcu5 + 3350 - tp.oe);
+ format[5] = (tp.o_vtsabb + 3350 - tp.oe);
+
+ for (i = 0; i < 6; i++)
+ x_roomt[i] = (((format[i] * 10000) / 4096) * 10000) / tp.gain;
+
+ temp0 = (10000 * 100000 / tp.gain) * 15 / 18;
+
+ if (tp.o_slope_sign == 0)
+ mts = (temp0 * 10) / (1534 + tp.o_slope * 10);
+ else
+ mts = (temp0 * 10) / (1534 - tp.o_slope * 10);
+
+ for (idx = 0; idx < svsp->bank_num; idx++) {
+ svsb = &svsp->banks[idx];
+ svsb->mts = mts;
+
+ switch (svsb->sw_id) {
+ case SVS_CPU_LITTLE:
+ tb_roomt = x_roomt[3];
+ break;
+ case SVS_CPU_BIG:
+ tb_roomt = x_roomt[4];
+ break;
+ case SVS_CCI:
+ tb_roomt = x_roomt[3];
+ break;
+ case SVS_GPU:
+ tb_roomt = x_roomt[1];
+ break;
+ default:
+ pr_err("unknown svsb_id = %u? disable svs\n",
+ svsb->sw_id);
+ return -EINVAL;
+ }
+
+ temp0 = (tp.degc_cali * 10 / 2);
+ temp1 = ((10000 * 100000 / 4096 / tp.gain) *
+ tp.oe + tb_roomt * 10) * 15 / 18;
+
+ if (tp.o_slope_sign == 0)
+ temp2 = temp1 * 100 / (1534 + tp.o_slope * 10);
+ else
+ temp2 = temp1 * 100 / (1534 - tp.o_slope * 10);
+
+ svsb->bts = (temp0 + temp2 - 250) * 4 / 10;
+ }
+
+ return 0;
+}
+
+static int svs_is_support(struct mtk_svs *svs)
+{
+ const struct svs_platform *svsp = svs->platform;
+ struct svs_bank *svsb;
+ struct nvmem_cell *cell;
+ size_t len;
+ int ret;
+ u32 idx, i;
+
+ if (svsp->fake_efuse) {
+ len = svsp->efuse_num * 4;
+ svs->efuse = kzalloc(len, GFP_KERNEL);
+ if (!svs->efuse)
+ return -ENOMEM;
+
+ len = svsp->thermal_efuse_num * 4;
+ svs->thermal_efuse = kzalloc(len, GFP_KERNEL);
+ if (!svs->thermal_efuse)
+ return -ENOMEM;
+
+ goto svsp_efuse_parsing;
+ }
+
+ /* get svs efuse by nvmem */
+ cell = nvmem_cell_get(svs->dev, "svs-calibration-data");
+ if (IS_ERR(cell)) {
+ pr_err("no \"svs-calibration-data\" from dts? disable svs\n");
+ return PTR_ERR(cell);
+ }
+
+ svs->efuse = (u32 *)nvmem_cell_read(cell, &len);
+ nvmem_cell_put(cell);
+
+ ret = (svs->efuse[svsp->efuse_check] == 0) ? -EPERM : 0;
+ if (ret) {
+ pr_err("no svs efuse. disable svs.\n");
+ for (i = 0; i < svsp->efuse_num; i++)
+ pr_err("M_HW_RES%d: 0x%08x\n", i, svs->efuse[i]);
+ return ret;
+ }
+
+ /* get thermal efuse by nvmem */
+ cell = nvmem_cell_get(svs->dev, "calibration-data");
+ if (IS_ERR(cell)) {
+ pr_err("no \"calibration-data\" from dts? disable mon mode\n");
+ svs->thermal_efuse = NULL;
+ for (idx = 0; idx < svsp->bank_num; idx++) {
+ svsb = &svsp->banks[idx];
+ svsb->mon_mode_support = false;
+ }
+ goto svsp_efuse_parsing;
+ }
+
+ svs->thermal_efuse = (u32 *)nvmem_cell_read(cell, &len);
+ nvmem_cell_put(cell);
+
+svsp_efuse_parsing:
+ ret = svsp->efuse_parsing(svs);
+
+ return ret;
+}
+
+static int svs_resource_setup(struct mtk_svs *svs)
+{
+ const struct svs_platform *svsp = svs->platform;
+ struct svs_bank *svsb;
+ struct platform_device *pdev;
+ struct device_node *np = NULL;
+ struct dev_pm_opp *opp;
+ unsigned long freq;
+ size_t opp_size;
+ int count, ret;
+ u32 idx, i;
+
+ for (idx = 0; idx < svsp->bank_num; idx++) {
+ svsb = &svsp->banks[idx];
+
+ if (!svsb->init01_support)
+ continue;
+
+ switch (svsb->sw_id) {
+ case SVS_CPU_LITTLE:
+ svsb->name = "SVS_CPU_LITTLE";
+ break;
+ case SVS_CPU_BIG:
+ svsb->name = "SVS_CPU_BIG";
+ break;
+ case SVS_CCI:
+ svsb->name = "SVS_CCI";
+ break;
+ case SVS_GPU:
+ svsb->name = "SVS_GPU";
+ break;
+ default:
+ WARN_ON(1);
+ return -EINVAL;
+ }
+
+ /* Add svs_bank device for opp-table/mtcmos/buck control */
+ pdev = platform_device_alloc(svsb->name, 0);
+ if (!pdev) {
+ pr_err("%s: fail to alloc pdev for svs_bank\n",
+ svsb->name);
+ return -ENOMEM;
+ }
+
+ for_each_child_of_node(svs->dev->of_node, np) {
+ if (of_device_is_compatible(np, svsb->of_compatible)) {
+ pdev->dev.of_node = np;
+ break;
+ }
+ }
+
+ ret = platform_device_add(pdev);
+ if (ret) {
+ pr_err("%s: fail to add svs_bank device: %d\n",
+ svsb->name, ret);
+ return ret;
+ }
+
+ svsb->dev = &pdev->dev;
+ dev_set_drvdata(svsb->dev, svs);
+ ret = dev_pm_opp_of_add_table(svsb->dev);
+ if (ret) {
+ pr_err("%s: fail to add opp table: %d\n",
+ svsb->name, ret);
+ return ret;
+ }
+
+ mutex_init(&svsb->lock);
+
+ svsb->buck = devm_regulator_get_optional(svsb->dev,
+ svsb->buck_name);
+ if (IS_ERR(svsb->buck)) {
+ pr_err("%s: cannot get regulator \"%s-supply\"\n",
+ svsb->name, svsb->buck_name);
+ return PTR_ERR(svsb->buck);
+ }
+
+ count = dev_pm_opp_get_opp_count(svsb->dev);
+ if (svsb->opp_count != count) {
+ pr_err("%s: opp_count not \"%u\" but get \"%d\"?\n",
+ svsb->name, svsb->opp_count, count);
+ return count;
+ }
+
+ opp_size = 4 * svsb->opp_count;
+ svsb->opp_volts = kmalloc(opp_size, GFP_KERNEL);
+ if (!svsb->opp_volts)
+ return -ENOMEM;
+
+ svsb->init02_volts = kmalloc(opp_size, GFP_KERNEL);
+ if (!svsb->init02_volts)
+ return -ENOMEM;
+
+ svsb->volts = kmalloc(opp_size, GFP_KERNEL);
+ if (!svsb->volts)
+ return -ENOMEM;
+
+ svsb->opp_freqs = kmalloc(opp_size, GFP_KERNEL);
+ if (!svsb->opp_freqs)
+ return -ENOMEM;
+
+ svsb->freqs_pct = kmalloc(opp_size, GFP_KERNEL);
+ if (!svsb->freqs_pct)
+ return -ENOMEM;
+
+ for (i = 0, freq = (u32)-1; i < svsb->opp_count; i++, freq--) {
+ opp = dev_pm_opp_find_freq_floor(svsb->dev, &freq);
+ if (IS_ERR(opp)) {
+ pr_err("%s: error opp entry!!, err = %ld\n",
+ svsb->name, PTR_ERR(opp));
+ return PTR_ERR(opp);
+ }
+
+ svsb->opp_freqs[i] = freq;
+ svsb->opp_volts[i] = dev_pm_opp_get_voltage(opp);
+ svsb->freqs_pct[i] = percent(svsb->opp_freqs[i],
+ svsb->freq_base) & 0xff;
+ }
+ }
+
+ return 0;
+}
+
+static int svs_suspend(struct device *dev)
+{
+ struct mtk_svs *svs = dev_get_drvdata(dev);
+ const struct svs_platform *svsp = svs->platform;
+ struct svs_bank *svsb;
+ unsigned long flags;
+ u32 idx;
+
+ /* Wait if there is processing svs_isr(). Suspend all banks. */
+ flags = claim_mtk_svs_lock();
+ for (idx = 0; idx < svsp->bank_num; idx++) {
+ svsb = &svsp->banks[idx];
+ svs->bank = svsb;
+ svs_switch_bank(svs);
+ svs_writel(svs, 0x0, SVSEN);
+ svs_writel(svs, 0x00ffffff, INTSTS);
+ svsb->suspended = true;
+ }
+ release_mtk_svs_lock(flags);
+
+ for (idx = 0; idx < svsp->bank_num; idx++) {
+ svsb = &svsp->banks[idx];
+ if (svsb->phase == SVS_PHASE_MON) {
+ svsb->phase = SVS_PHASE_INIT02;
+ svs_set_volts(svsb, true);
+ }
+ }
+
+ clk_disable_unprepare(svs->main_clk);
+
+ return 0;
+}
+
+static int svs_resume(struct device *dev)
+{
+ struct mtk_svs *svs = dev_get_drvdata(dev);
+ const struct svs_platform *svsp = svs->platform;
+ struct svs_bank *svsb;
+ int ret;
+ u32 idx;
+
+ ret = clk_prepare_enable(svs->main_clk);
+ if (ret)
+ pr_err("%s(): cannot enable main_clk\n", __func__);
+
+ for (idx = 0; idx < svsp->bank_num; idx++) {
+ svsb = &svsp->banks[idx];
+ svsb->suspended = false;
+ }
+
+ ret = svs_init02(svs);
+ if (ret)
+ return ret;
+
+ svs_mon_mode(svs);
+
+ return 0;
+}
+
+static int svs_debug_proc_show(struct seq_file *m, void *v)
+{
+ struct svs_bank *svsb = (struct svs_bank *)m->private;
+
+ if (svsb->phase == SVS_PHASE_INIT01)
+ seq_puts(m, "init1\n");
+ else if (svsb->phase == SVS_PHASE_INIT02)
+ seq_puts(m, "init2\n");
+ else if (svsb->phase == SVS_PHASE_MON)
+ seq_puts(m, "mon mode\n");
+ else if (svsb->phase == SVS_PHASE_ERROR)
+ seq_puts(m, "disabled\n");
+ else
+ seq_puts(m, "unknown\n");
+
+ return 0;
+}
+
+static ssize_t svs_debug_proc_write(struct file *file,
+ const char __user *buffer,
+ size_t count, loff_t *pos)
+{
+ struct svs_bank *svsb = (struct svs_bank *)PDE_DATA(file_inode(file));
+ struct mtk_svs *svs = dev_get_drvdata(svsb->dev);
+ char *buf = (char *)__get_free_page(GFP_USER);
+ unsigned long flags;
+ int enabled, ret;
+
+ if (svsb->phase == SVS_PHASE_ERROR)
+ return count;
+
+ if (!buf)
+ return -ENOMEM;
+
+ if (count >= PAGE_SIZE) {
+ free_page((unsigned long)buf);
+ return -EINVAL;
+ }
+
+ if (copy_from_user(buf, buffer, count)) {
+ free_page((unsigned long)buf);
+ return -EFAULT;
+ }
+
+ buf[count] = '\0';
+
+ ret = kstrtoint(buf, 10, &enabled);
+ if (ret)
+ return ret;
+
+ if (!enabled) {
+ flags = claim_mtk_svs_lock();
+ svs->bank = svsb;
+
+ svsb->init01_support = false;
+ svsb->init02_support = false;
+ svsb->mon_mode_support = false;
+
+ svs_switch_bank(svs);
+ svs_writel(svs, 0x0, SVSEN);
+ svs_writel(svs, 0x00ffffff, INTSTS);
+ release_mtk_svs_lock(flags);
+ }
+
+ svsb->phase = SVS_PHASE_ERROR;
+ svs_set_volts(svsb, true);
+
+ return count;
+}
+
+proc_fops_rw(svs_debug);
+
+static int svs_dump_proc_show(struct seq_file *m, void *v)
+{
+ struct mtk_svs *svs = (struct mtk_svs *)m->private;
+ const struct svs_platform *svsp = svs->platform;
+ struct svs_bank *svsb;
+ unsigned long svs_reg_addr;
+ u32 idx, i, j;
+
+ for (i = 0; i < svsp->efuse_num; i++) {
+ if (svs->efuse[i])
+ seq_printf(m, "M_HW_RES%d = 0x%08x\n",
+ i, svs->efuse[i]);
+ }
+
+ for (i = 0; i < svsp->thermal_efuse_num; i++) {
+ if (svs->thermal_efuse && svs->thermal_efuse[i])
+ seq_printf(m, "THERMAL_EFUSE%d = 0x%08x\n",
+ i, svs->thermal_efuse[i]);
+ }
+
+ for (idx = 0; idx < svsp->bank_num; idx++) {
+ svsb = &svsp->banks[idx];
+
+ if (!svsb->init01_support)
+ continue;
+
+ for (i = SVS_PHASE_INIT01; i <= SVS_PHASE_MON; i++) {
+ seq_printf(m, "Bank_number = %u\n", svsb->hw_id);
+
+ if (i < SVS_PHASE_MON)
+ seq_printf(m, "mode = init%d\n", i + 1);
+ else
+ seq_puts(m, "mode = mon\n");
+
+ for (j = TEMPMONCTL0; j < reg_num; j++) {
+ svs_reg_addr = (unsigned long)(svs->base +
+ svsp->regs[j]);
+ seq_printf(m, "0x%08lx = 0x%08x\n",
+ svs_reg_addr, svsb->reg_data[i][j]);
+ }
+ }
+ }
+
+ return 0;
+}
+
+proc_fops_ro(svs_dump);
+
+static int svs_status_proc_show(struct seq_file *m, void *v)
+{
+ struct svs_bank *svsb = (struct svs_bank *)m->private;
+ struct dev_pm_opp *opp;
+ unsigned long freq;
+ int zone_temp, ret;
+ u32 i;
+
+ ret = svs_get_zone_temperature(svsb, &zone_temp);
+ if (ret)
+ seq_printf(m, "%s: cannot get zone \"%s\" temperature\n",
+ svsb->name, svsb->zone_name);
+ else
+ seq_printf(m, "%s: temperature = %d\n", svsb->name, zone_temp);
+
+ for (i = 0, freq = (u32)-1; i < svsb->opp_count; i++, freq--) {
+ opp = dev_pm_opp_find_freq_floor(svsb->dev, &freq);
+ if (IS_ERR(opp)) {
+ seq_printf(m, "%s: error opp entry!!, err = %ld\n",
+ svsb->name, PTR_ERR(opp));
+ return PTR_ERR(opp);
+ }
+
+ seq_printf(m, "opp_freqs[%02u]: %lu, volts[%02u]: %lu, ",
+ i, freq, i, dev_pm_opp_get_voltage(opp));
+ seq_printf(m, "svsb_volts[%02u]: 0x%x, freqs_pct[%02u]: %u\n",
+ i, svsb->volts[i], i, svsb->freqs_pct[i]);
+ }
+
+ return 0;
+}
+
+proc_fops_ro(svs_status);
+
+static int svs_volt_offset_proc_show(struct seq_file *m, void *v)
+{
+ struct svs_bank *svsb = (struct svs_bank *)m->private;
+
+ seq_printf(m, "%d\n", svsb->volt_offset);
+
+ return 0;
+}
+
+static ssize_t svs_volt_offset_proc_write(struct file *file,
+ const char __user *buffer,
+ size_t count, loff_t *pos)
+{
+ struct svs_bank *svsb = (struct svs_bank *)PDE_DATA(file_inode(file));
+ char *buf = (char *)__get_free_page(GFP_USER);
+ int ret, volt_offset;
+
+ if (!buf)
+ return -ENOMEM;
+
+ if (count >= PAGE_SIZE) {
+ free_page((unsigned long)buf);
+ return -EINVAL;
+ }
+
+ if (copy_from_user(buf, buffer, count)) {
+ free_page((unsigned long)buf);
+ return -EFAULT;
+ }
+
+ buf[count] = '\0';
+
+ if (!kstrtoint(buf, 10, &volt_offset)) {
+ svsb->volt_offset = volt_offset;
+ ret = svs_set_volts(svsb, true);
+ if (ret)
+ return ret;
+ }
+
+ return count;
+}
+
+proc_fops_rw(svs_volt_offset);
+
+static int svs_create_svs_procfs(struct mtk_svs *svs)
+{
+ const struct svs_platform *svsp = svs->platform;
+ struct svs_bank *svsb;
+ struct proc_dir_entry *svs_dir, *bank_dir;
+ u32 idx, i;
+
+ struct pentry {
+ const char *name;
+ const struct file_operations *fops;
+ };
+
+ struct pentry svs_entries[] = {
+ proc_entry(svs_dump),
+ };
+
+ struct pentry bank_entries[] = {
+ proc_entry(svs_debug),
+ proc_entry(svs_status),
+ proc_entry(svs_volt_offset),
+ };
+
+ svs_dir = proc_mkdir("svs", NULL);
+ if (!svs_dir) {
+ pr_err("mkdir /proc/svs failed\n");
+ return -EPERM;
+ }
+
+ for (i = 0; i < ARRAY_SIZE(svs_entries); i++) {
+ if (!proc_create_data(svs_entries[i].name, 0664,
+ svs_dir, svs_entries[i].fops, svs)) {
+ pr_err("create /proc/svs/%s failed\n",
+ svs_entries[i].name);
+ return -EPERM;
+ }
+ }
+
+ for (idx = 0; idx < svsp->bank_num; idx++) {
+ svsb = &svsp->banks[idx];
+
+ if (!svsb->init01_support)
+ continue;
+
+ bank_dir = proc_mkdir(svsb->name, svs_dir);
+ if (!bank_dir) {
+ pr_err("mkdir /proc/svs/%s failed\n", svsb->name);
+ return -EPERM;
+ }
+
+ for (i = 0; i < ARRAY_SIZE(bank_entries); i++) {
+ if (!proc_create_data(bank_entries[i].name, 0664,
+ bank_dir, bank_entries[i].fops,
+ svsb)) {
+ pr_err("create /proc/svs/%s/%s failed\n",
+ svsb->name, bank_entries[i].name);
+ return -EPERM;
+ }
+ }
+ }
+
+ return 0;
+}
+
+struct svs_bank_ops svs_mt8183_banks_ops = {
+ .set_freqs_pct = svs_set_freqs_pct_v2,
+ .get_vops = svs_get_vops_v2,
+};
+
+struct svs_bank svs_mt8183_banks[4] = {
+ {
+ .of_compatible = "mediatek,mt8183-svs-cpu-little",
+ .sw_id = SVS_CPU_LITTLE,
+ .hw_id = 0,
+ .ops = &svs_mt8183_banks_ops,
+ .zone_name = "tzts4",
+ .buck_name = "vcpu-little",
+ .mtcmos_request = false,
+ .init01_volt_flag = SVS_INIT01_VOLT_INC_ONLY,
+ .init01_support = true,
+ .init02_support = true,
+ .mon_mode_support = false,
+ .opp_count = 16,
+ .freq_base = 1989000000,
+ .vboot = 0x30,
+ .volt_step = 6250,
+ .volt_base = 500000,
+ .volt_offset = 0,
+ .vmax = 0x64,
+ .vmin = 0x18,
+ .dthi = 0x1,
+ .dtlo = 0xfe,
+ .det_window = 0xa28,
+ .det_max = 0xffff,
+ .age_config = 0x555555,
+ .agem = 0x0,
+ .dc_config = 0x555555,
+ .dvt_fixed = 0x7,
+ .vco = 0x10,
+ .chkshift = 0x77,
+ .upper_temp_bound = 0x64,
+ .lower_temp_bound = 0xb2,
+ .low_temp_threashold = 25000,
+ .low_temp_offset = 0,
+ .coresel = 0x8fff0000,
+ .systemclk_en = BIT(31),
+ .intst = BIT(0),
+ .ctl0 = 0x00010001,
+ },
+ {
+ .of_compatible = "mediatek,mt8183-svs-cpu-big",
+ .sw_id = SVS_CPU_BIG,
+ .hw_id = 1,
+ .ops = &svs_mt8183_banks_ops,
+ .zone_name = "tzts5",
+ .buck_name = "vcpu-big",
+ .mtcmos_request = false,
+ .init01_volt_flag = SVS_INIT01_VOLT_INC_ONLY,
+ .init01_support = true,
+ .init02_support = true,
+ .mon_mode_support = false,
+ .opp_count = 16,
+ .freq_base = 1989000000,
+ .vboot = 0x30,
+ .volt_step = 6250,
+ .volt_base = 500000,
+ .volt_offset = 0,
+ .vmax = 0x58,
+ .vmin = 0x10,
+ .dthi = 0x1,
+ .dtlo = 0xfe,
+ .det_window = 0xa28,
+ .det_max = 0xffff,
+ .age_config = 0x555555,
+ .agem = 0x0,
+ .dc_config = 0x555555,
+ .dvt_fixed = 0x7,
+ .vco = 0x10,
+ .chkshift = 0x77,
+ .upper_temp_bound = 0x64,
+ .lower_temp_bound = 0xb2,
+ .low_temp_threashold = 25000,
+ .low_temp_offset = 0,
+ .coresel = 0x8fff0001,
+ .systemclk_en = BIT(31),
+ .intst = BIT(1),
+ .ctl0 = 0x00000001,
+ },
+ {
+ .of_compatible = "mediatek,mt8183-svs-cci",
+ .sw_id = SVS_CCI,
+ .hw_id = 2,
+ .ops = &svs_mt8183_banks_ops,
+ .zone_name = "tzts4",
+ .buck_name = "vcci",
+ .mtcmos_request = false,
+ .init01_volt_flag = SVS_INIT01_VOLT_INC_ONLY,
+ .init01_support = true,
+ .init02_support = true,
+ .mon_mode_support = false,
+ .opp_count = 16,
+ .freq_base = 1196000000,
+ .vboot = 0x30,
+ .volt_step = 6250,
+ .volt_base = 500000,
+ .volt_offset = 0,
+ .vmax = 0x64,
+ .vmin = 0x18,
+ .dthi = 0x1,
+ .dtlo = 0xfe,
+ .det_window = 0xa28,
+ .det_max = 0xffff,
+ .age_config = 0x555555,
+ .agem = 0x0,
+ .dc_config = 0x555555,
+ .dvt_fixed = 0x7,
+ .vco = 0x10,
+ .chkshift = 0x77,
+ .upper_temp_bound = 0x64,
+ .lower_temp_bound = 0xb2,
+ .low_temp_threashold = 25000,
+ .low_temp_offset = 0,
+ .coresel = 0x8fff0002,
+ .systemclk_en = BIT(31),
+ .intst = BIT(2),
+ .ctl0 = 0x00100003,
+ },
+ {
+ .of_compatible = "mediatek,mt8183-svs-gpu",
+ .sw_id = SVS_GPU,
+ .hw_id = 3,
+ .ops = &svs_mt8183_banks_ops,
+ .zone_name = "tzts2",
+ .buck_name = "vgpu",
+ .mtcmos_request = true,
+ .init01_volt_flag = SVS_INIT01_VOLT_INC_ONLY,
+ .init01_support = true,
+ .init02_support = true,
+ .mon_mode_support = true,
+ .opp_count = 16,
+ .freq_base = 900000000,
+ .vboot = 0x30,
+ .volt_step = 6250,
+ .volt_base = 500000,
+ .volt_offset = 0,
+ .vmax = 0x40,
+ .vmin = 0x14,
+ .dthi = 0x1,
+ .dtlo = 0xfe,
+ .det_window = 0xa28,
+ .det_max = 0xffff,
+ .age_config = 0x555555,
+ .agem = 0x0,
+ .dc_config = 0x555555,
+ .dvt_fixed = 0x3,
+ .vco = 0x10,
+ .chkshift = 0x77,
+ .upper_temp_bound = 0x64,
+ .lower_temp_bound = 0xb2,
+ .low_temp_threashold = 25000,
+ .low_temp_offset = 3,
+ .coresel = 0x8fff0003,
+ .systemclk_en = BIT(31),
+ .intst = BIT(3),
+ .ctl0 = 0x00050001,
+ },
+};
+
+static const struct svs_platform svs_mt8183_platform = {
+ .name = "mt8183-svs",
+ .banks = svs_mt8183_banks,
+ .efuse_parsing = svs_mt8183_efuse_parsing,
+ .regs = svs_regs_v2,
+ .fake_efuse = false,
+ .bank_num = 4,
+ .efuse_num = 25,
+ .efuse_check = 2,
+ .thermal_efuse_num = 3,
+};
+
+static const struct of_device_id mtk_svs_of_match[] = {
+ {
+ .compatible = "mediatek,mt8183-svs",
+ .data = &svs_mt8183_platform,
+ }, {
+ /* sentinel */
+ },
+};
+
+static int svs_probe(struct platform_device *pdev)
+{
+ const struct of_device_id *of_dev_id;
+ struct mtk_svs *svs;
+ int ret;
+ u32 svs_irq;
+
+ svs = devm_kzalloc(&pdev->dev, sizeof(*svs), GFP_KERNEL);
+ if (!svs)
+ return -ENOMEM;
+
+ svs->dev = &pdev->dev;
+ if (!svs->dev->of_node) {
+ pr_err("cannot find device node\n");
+ return -ENODEV;
+ }
+
+ svs->base = of_iomap(svs->dev->of_node, 0);
+ if (IS_ERR(svs->base)) {
+ pr_err("cannot find svs register base\n");
+ return PTR_ERR(svs->base);
+ }
+
+ svs_irq = irq_of_parse_and_map(svs->dev->of_node, 0);
+ ret = devm_request_threaded_irq(svs->dev, svs_irq, NULL, svs_isr,
+ IRQF_TRIGGER_LOW | IRQF_ONESHOT,
+ "mtk-svs", svs);
+ if (ret) {
+ pr_err("register irq(%d) failed: %d\n", svs_irq, ret);
+ return ret;
+ }
+
+ of_dev_id = of_match_node(mtk_svs_of_match, svs->dev->of_node);
+ if (!of_dev_id || !of_dev_id->data)
+ return -EINVAL;
+
+ svs->platform = of_dev_id->data;
+ dev_set_drvdata(svs->dev, svs);
+
+ svs->main_clk = devm_clk_get(svs->dev, "main_clk");
+ if (IS_ERR(svs->main_clk)) {
+ pr_err("failed to get clock: %ld\n", PTR_ERR(svs->main_clk));
+ return PTR_ERR(svs->main_clk);
+ }
+
+ ret = clk_prepare_enable(svs->main_clk);
+ if (ret) {
+ pr_err("cannot enable main_clk: %d\n", ret);
+ return ret;
+ }
+
+ ret = svs_is_support(svs);
+ if (ret)
+ goto svs_probe_fail;
+
+ ret = svs_resource_setup(svs);
+ if (ret)
+ goto svs_probe_fail;
+
+ ret = svs_start(svs);
+ if (ret)
+ goto svs_probe_fail;
+
+ ret = svs_create_svs_procfs(svs);
+ if (ret)
+ goto svs_probe_fail;
+
+ return 0;
+
+svs_probe_fail:
+ clk_disable_unprepare(svs->main_clk);
+
+ return ret;
+}
+
+static const struct dev_pm_ops svs_pm_ops = {
+ .suspend = svs_suspend,
+ .resume = svs_resume,
+};
+
+static struct platform_driver svs_driver = {
+ .probe = svs_probe,
+ .driver = {
+ .name = "mtk-svs",
+ .pm = &svs_pm_ops,
+ .of_match_table = of_match_ptr(mtk_svs_of_match),
+ },
+};
+
+static int __init svs_init(void)
+{
+ int ret;
+
+ ret = platform_driver_register(&svs_driver);
+ if (ret) {
+ pr_err("svs platform driver register failed: %d\n", ret);
+ return ret;
+ }
+
+ return 0;
+}
+
+late_initcall_sync(svs_init);
+
+MODULE_DESCRIPTION("MediaTek SVS Driver v1.0");
+MODULE_LICENSE("GPL");
diff --git a/include/linux/power/mtk_svs.h b/include/linux/power/mtk_svs.h
new file mode 100644
index 000000000000..d5efca8d9dca
--- /dev/null
+++ b/include/linux/power/mtk_svs.h
@@ -0,0 +1,23 @@
+/* SPDX-License-Identifier: GPL-2.0
+ *
+ * Copyright (C) 2018 MediaTek Inc.
+ */
+
+#ifndef __MTK_SVS_H__
+#define __MTK_SVS_H__
+
+#if defined(CONFIG_MTK_SVS)
+unsigned long claim_mtk_svs_lock(void);
+void release_mtk_svs_lock(unsigned long flags);
+#else
+static inline unsigned long claim_mtk_svs_lock(void)
+{
+ return 0;
+}
+
+static inline void release_mtk_svs_lock(unsigned long flags)
+{
+}
+#endif /* CONFIG_MTK_SVS */
+
+#endif /* __MTK_SVS_H__ */
--
2.18.0
^ permalink raw reply related
* [PATCH v4 1/2] dt-bindings: soc: add mtk svs dt-bindings
From: Roger Lu @ 2019-07-29 8:20 UTC (permalink / raw)
To: Kevin Hilman, Rob Herring, Nicolas Boichat, Stephen Boyd
Cc: Fan Chen, HenryC Chen, yt.lee, Angus Lin, Mark Rutland,
Matthias Brugger, Nishanth Menon, Roger Lu, devicetree,
linux-arm-kernel, linux-mediatek, linux-kernel, linux-pm
In-Reply-To: <20190729082032.13661-1-roger.lu@mediatek.com>
Document the binding for enabling mtk svs on MediaTek SoC.
Signed-off-by: Roger Lu <roger.lu@mediatek.com>
---
.../devicetree/bindings/power/mtk-svs.txt | 88 +++++++++++++++++++
1 file changed, 88 insertions(+)
create mode 100644 Documentation/devicetree/bindings/power/mtk-svs.txt
diff --git a/Documentation/devicetree/bindings/power/mtk-svs.txt b/Documentation/devicetree/bindings/power/mtk-svs.txt
new file mode 100644
index 000000000000..6a71992ef162
--- /dev/null
+++ b/Documentation/devicetree/bindings/power/mtk-svs.txt
@@ -0,0 +1,88 @@
+* Mediatek Smart Voltage Scaling (MTK SVS)
+
+This describes the device tree binding for the MTK SVS controller (bank)
+which helps provide the optimized CPU/GPU/CCI voltages. This device also
+needs thermal data to calculate thermal slope for accurately compensate
+the voltages when temperature change.
+
+Required properties:
+- compatible:
+ - "mediatek,mt8183-svs" : For MT8183 family of SoCs
+- reg: Address range of the MTK SVS controller.
+- interrupts: IRQ for the MTK SVS controller.
+- clocks, clock-names: Clocks needed for the svs controller. required
+ clocks are:
+ "main_clk": Main clock needed for register access
+- nvmem-cells: Phandle to the calibration data provided by a nvmem device.
+- nvmem-cell-names: Should be "svs-calibration-data" and "calibration-data"
+
+Subnodes:
+- svs_cpu_little: SVS bank device node of little CPU
+ compatible: "mediatek,mt8183-svs-cpu-little"
+ operating-points-v2: OPP table hooked by SVS little CPU bank.
+ SVS will optimze this OPP table voltage part.
+ vcpu-little-supply: PMIC buck of little CPU
+- svs_cpu_big: SVS bank device node of big CPU
+ compatible: "mediatek,mt8183-svs-cpu-big"
+ operating-points-v2: OPP table hooked by SVS big CPU bank.
+ SVS will optimze this OPP table voltage part.
+ vcpu-big-supply: PMIC buck of big CPU
+- svs_cci: SVS bank device node of CCI
+ compatible: "mediatek,mt8183-svs-cci"
+ operating-points-v2: OPP table hooked by SVS CCI bank.
+ SVS will optimze this OPP table voltage part.
+ vcci-supply: PMIC buck of CCI
+- svs_gpu: SVS bank device node of GPU
+ compatible: "mediatek,mt8183-svs-gpu"
+ operating-points-v2: OPP table hooked by SVS GPU bank.
+ SVS will optimze this OPP table voltage part.
+ vgpu-spply: PMIC buck of GPU
+
+Example:
+
+ svs: svs@1100b000 {
+ compatible = "mediatek,mt8183-svs";
+ reg = <0 0x1100b000 0 0x1000>;
+ interrupts = <GIC_SPI 127 IRQ_TYPE_LEVEL_LOW 0>;
+ clocks = <&infracfg CLK_INFRA_THERM>;
+ clock-names = "main_clk";
+ nvmem-cells = <&svs_calibration>, <&thermal_calibration>;
+ nvmem-cell-names = "svs-calibration-data", "calibration-data";
+
+ svs_cpu_little: svs_cpu_little {
+ compatible = "mediatek,mt8183-svs-cpu-little";
+ operating-points-v2 = <&cluster0_opp>;
+ };
+
+ svs_cpu_big: svs_cpu_big {
+ compatible = "mediatek,mt8183-svs-cpu-big";
+ operating-points-v2 = <&cluster1_opp>;
+ };
+
+ svs_cci: svs_cci {
+ compatible = "mediatek,mt8183-svs-cci";
+ operating-points-v2 = <&cci_opp>;
+ };
+
+ svs_gpu: svs_gpu {
+ compatible = "mediatek,mt8183-svs-gpu";
+ power-domains = <&scpsys MT8183_POWER_DOMAIN_MFG_2D>;
+ operating-points-v2 = <&gpu_opp_table>;
+ };
+ };
+
+ &svs_cpu_little {
+ vcpu-little-supply = <&mt6358_vproc12_reg>;
+ };
+
+ &svs_cpu_big {
+ vcpu-big-supply = <&mt6358_vproc11_reg>;
+ };
+
+ &svs_cci {
+ vcci-supply = <&mt6358_vproc12_reg>;
+ };
+
+ &svs_gpu {
+ vgpu-spply = <&mt6358_vgpu_reg>;
+ };
--
2.18.0
^ permalink raw reply related
* PM / AVS: SVS: Introduce SVS engine
From: Roger Lu @ 2019-07-29 8:20 UTC (permalink / raw)
To: Kevin Hilman, Rob Herring, Nicolas Boichat, Stephen Boyd
Cc: Mark Rutland, Nishanth Menon, Angus Lin, devicetree, linux-pm,
Roger Lu, linux-kernel, HenryC Chen, yt.lee, Fan Chen,
linux-mediatek, Matthias Brugger, linux-arm-kernel
SVS driver use OPP adjust event in [1] to update OPP table voltage part.
[1] https://patchwork.kernel.org/patch/10946069/
changes since v3:
- return -ENOMEM when kmalloc() cannot allocate memory.
- Refine SVS debug log format for SVS designer request.
Roger Lu (2):
dt-bindings: soc: add mtk svs dt-bindings
PM / AVS: SVS: Introduce SVS engine
.../devicetree/bindings/power/mtk-svs.txt | 88 +
drivers/power/avs/Kconfig | 10 +
drivers/power/avs/Makefile | 1 +
drivers/power/avs/mtk_svs.c | 2075 +++++++++++++++++
include/linux/power/mtk_svs.h | 23 +
5 files changed, 2197 insertions(+)
create mode 100644 Documentation/devicetree/bindings/power/mtk-svs.txt
create mode 100644 drivers/power/avs/mtk_svs.c
create mode 100644 include/linux/power/mtk_svs.h
^ permalink raw reply
* Re: [PATCH v2 2/2] dt-bindings: usb: renesas_gen3: Rename bindings documentation file
From: Simon Horman @ 2019-07-29 8:14 UTC (permalink / raw)
To: Yoshihiro Shimoda
Cc: Greg Kroah-Hartman, Geert Uytterhoeven, Kuninori Morimoto,
Magnus Damm, USB list, Linux-Renesas, Rob Herring, Mark Rutland,
open list:OPEN FIRMWARE AND FLATTENED DEVICE TREE BINDINGS,
Niklas Söderlund
In-Reply-To: <TYAPR01MB4544F226C06730C5611EB025D8C00@TYAPR01MB4544.jpnprd01.prod.outlook.com>
On Fri, Jul 26, 2019 at 01:22:48AM +0000, Yoshihiro Shimoda wrote:
> Hi Greg,
>
> > From: Greg Kroah-Hartman, Sent: Thursday, July 25, 2019 6:10 PM
> >
> > On Thu, Jul 11, 2019 at 10:03:03AM +0200, Simon Horman wrote:
> > > On Wed, Jul 03, 2019 at 02:28:51PM +0200, Geert Uytterhoeven wrote:
> > > > Hi Simon,
> > > >
> > > > On Wed, Jul 3, 2019 at 10:35 AM Simon Horman <horms+renesas@verge.net.au> wrote:
> > > > > For consistency with the naming of (most) other documentation files for DT
> > > > > bindings for Renesas IP blocks rename the Renesas USB3.0 peripheral
> > > > > documentation file from renesas-gen3.txt to renesas,usb3-peri.txt
> > > > >
> > > > > Signed-off-by: Simon Horman <horms+renesas@verge.net.au>
> > > > > Reviewed-by: Geert Uytterhoeven <geert+renesas@glider.be>
> > > > > Reviewed-by: Yoshihiro Shimoda <yoshihiro.shimoda.uh@renesas.com>
> > > > > Reviewed-by: Niklas Söderlund <niklas.soderlund+renesas@ragnatech.se>
> > > > >
> > > > > ---
> > > > > v2
> > > > > * Accumulate review tags
> > > > > * Use renesas,usb3-peri.txt as new filename as suggested by Shimoda-san
> > > >
> > > > Unfortunately the previous version has already made it into usb-next
> > > > 23c46801d14cb647 dt-bindings: usb: renesas_gen3: Rename bindings
> > > > documentation file
> > >
> > > Ok, I guess we should go with that version.
> >
> > So can you resend this series based on 5.3-rc1 so I know what to apply?
>
> Since your usb-testing branch already has it which is merged from Felipe's usb-next branch,
> I don't think Simon has to resend this series.
>
> https://www.spinics.net/lists/linux-usb/msg182103.html
Thanks and sorry for the confusion.
In v5.2-rc1 we had:
devicetree/bindings/usb/renesas_usb3.txt
devicetree/bindings/usb/renesas_usbhs.txt
In v5.3-rc1 we have:
devicetree/bindings/usb/renesas,usb3.txt
devicetree/bindings/usb/renesas,usbhs.txt
Which reflects v1 of this patchset. And I think this is an improvement.
Shimoda-san, can you let me know if you would like me to rebase v2
on v5.3-rc1? That would would give us:
devicetree/bindings/usb/renesas,usb3-peri.txt
devicetree/bindings/usb/renesas,usbhs.txt [unchanged]
^ permalink raw reply
* Re: [PATCH 5/6] clk: imx8mq: Remove CLK_IS_CRITICAL flag for IMX8MQ_CLK_TMU_ROOT
From: Daniel Baluta @ 2019-07-29 8:13 UTC (permalink / raw)
To: Anson Huang
Cc: Abel Vesa, rui.zhang@intel.com, edubezval@gmail.com,
daniel.lezcano@linaro.org, Rob Herring, Mark Rutland, Shawn Guo,
Sascha Hauer, Pengutronix Kernel Team, Fabio Estevam,
Michael Turquette, Stephen Boyd, Lucas Stach, Andrey Smirnov,
Angus Ainslie (Purism), Carlo Caione, Guido Günther,
Leonard Crestez, linux-pm
In-Reply-To: <DB3PR0402MB3916F32F03E542AEFBD39A43F5DD0@DB3PR0402MB3916.eurprd04.prod.outlook.com>
On Mon, Jul 29, 2019 at 10:49 AM Anson Huang <anson.huang@nxp.com> wrote:
> > We are all set then. Thanks Anson for clarifications!
>
> Thanks, so we are all clear about this issue, need to wait thermal maintainer to review
> the rest patch in this series, but I did NOT receive any response from thermal sub-system
> maintainer for really long time, NOT sure when the thermal patches can be accepted.
This is really unfortunate. I think it is safe to do a RESEND of the
patches as it has
been at least 3 weeks since your first send them.
Pick any reviewed-by you got and do a resend.
^ permalink raw reply
* Re: [PATCH 4/6] thermal: qoriq: Add clock operations
From: Guido Günther @ 2019-07-29 8:12 UTC (permalink / raw)
To: Anson.Huang
Cc: rui.zhang, edubezval, daniel.lezcano, robh+dt, mark.rutland,
shawnguo, s.hauer, kernel, festevam, mturquette, sboyd, l.stach,
abel.vesa, andrew.smirnov, angus, ccaione, leonard.crestez,
linux-pm, devicetree, linux-kernel, linux-arm-kernel, linux-clk,
Linux-imx
In-Reply-To: <20190705045612.27665-4-Anson.Huang@nxp.com>
Hi Anson,
On Fri, Jul 05, 2019 at 12:56:10PM +0800, Anson.Huang@nxp.com wrote:
> From: Anson Huang <Anson.Huang@nxp.com>
>
> Some platforms like i.MX8MQ has clock control for this module,
> need to add clock operations to make sure the driver is working
> properly.
>
> Signed-off-by: Anson Huang <Anson.Huang@nxp.com>
> ---
> drivers/thermal/qoriq_thermal.c | 24 ++++++++++++++++++++++++
> 1 file changed, 24 insertions(+)
>
> diff --git a/drivers/thermal/qoriq_thermal.c b/drivers/thermal/qoriq_thermal.c
> index 2b2f79b..0813c1b 100644
> --- a/drivers/thermal/qoriq_thermal.c
> +++ b/drivers/thermal/qoriq_thermal.c
> @@ -2,6 +2,7 @@
> //
> // Copyright 2016 Freescale Semiconductor, Inc.
>
> +#include <linux/clk.h>
> #include <linux/module.h>
> #include <linux/platform_device.h>
> #include <linux/err.h>
> @@ -72,6 +73,7 @@ struct qoriq_sensor {
>
> struct qoriq_tmu_data {
> struct qoriq_tmu_regs __iomem *regs;
> + struct clk *clk;
> bool little_endian;
> struct qoriq_sensor *sensor[SITES_MAX];
> };
> @@ -208,6 +210,19 @@ static int qoriq_tmu_probe(struct platform_device *pdev)
> return PTR_ERR(data->regs);
> }
>
> + data->clk = devm_clk_get(&pdev->dev, NULL);
> + if (IS_ERR(data->clk)) {
> + if (PTR_ERR(data->clk) == -EPROBE_DEFER)
> + return -EPROBE_DEFER;
> + data->clk = NULL;
> + }
Wouldn't devm_clk_get_optional make more sense?
> +
> + ret = clk_prepare_enable(data->clk);
> + if (ret) {
> + dev_err(&pdev->dev, "Failed to enable clock\n");
> + return ret;
> + }
> +
> qoriq_tmu_init_device(data); /* TMU initialization */
>
> ret = qoriq_tmu_calibration(pdev); /* TMU calibration */
> @@ -235,6 +250,8 @@ static int qoriq_tmu_remove(struct platform_device *pdev)
> /* Disable monitoring */
> tmu_write(data, TMR_DISABLE, &data->regs->tmr);
>
> + clk_disable_unprepare(data->clk);
> +
> platform_set_drvdata(pdev, NULL);
>
> return 0;
> @@ -250,14 +267,21 @@ static int __maybe_unused qoriq_tmu_suspend(struct device *dev)
> tmr &= ~TMR_ME;
> tmu_write(data, tmr, &data->regs->tmr);
>
> + clk_disable_unprepare(data->clk);
> +
> return 0;
> }
>
> static int __maybe_unused qoriq_tmu_resume(struct device *dev)
> {
> u32 tmr;
> + int ret;
> struct qoriq_tmu_data *data = dev_get_drvdata(dev);
>
> + ret = clk_prepare_enable(data->clk);
> + if (ret)
> + return ret;
> +
> /* Enable monitoring */
> tmr = tmu_read(data, &data->regs->tmr);
> tmr |= TMR_ME;
Apart from that it looks like what Fabio sent and what i tested so
Reviewed-by: Guido Günther <agx@sigxcpu.org>
Cheers,
-- Guido
> --
> 2.7.4
>
>
> _______________________________________________
> linux-arm-kernel mailing list
> linux-arm-kernel@lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
>
^ permalink raw reply
* Re: [PATCH v2 01/19] phy: mvebu-cp110-comphy: Add clocks support
From: Grzegorz Jaszczyk @ 2019-07-29 8:10 UTC (permalink / raw)
To: Miquel Raynal
Cc: Andrew Lunn, Jason Cooper, devicetree, Antoine Tenart,
Gregory Clement, Russell King, Kishon Vijay Abraham I,
Nadav Haklai, Rob Herring, Thomas Petazzoni, Maxime Chevallier,
linux-arm-kernel, Sebastian Hesselbarth
In-Reply-To: <20190627095104.22529-2-miquel.raynal@bootlin.com>
Hi Miquel
czw., 27 cze 2019 o 11:51 Miquel Raynal <miquel.raynal@bootlin.com> napisał(a):
> +static int mvebu_comphy_init_clks(struct mvebu_comphy_priv *priv)
> +{
> + int ret;
> +
> + priv->mg_domain_clk = devm_clk_get(priv->dev, "mg_clk");
> + if (IS_ERR(priv->mg_domain_clk))
> + return PTR_ERR(priv->mg_domain_clk);
> +
> + ret = clk_prepare_enable(priv->mg_domain_clk);
> + if (ret < 0)
> + return ret;
> +
> + priv->mg_core_clk = devm_clk_get(priv->dev, "mg_core_clk");
> + if (IS_ERR(priv->mg_core_clk)) {
> + ret = PTR_ERR(priv->mg_core_clk);
> + goto dis_mg_domain_clk;
> + }
> +
> + ret = clk_prepare_enable(priv->mg_core_clk);
> + if (ret < 0)
> + goto dis_mg_domain_clk;
> +
> + priv->axi_clk = devm_clk_get(priv->dev, "axi_clk");
> + if (IS_ERR(priv->axi_clk)) {
> + ret = PTR_ERR(priv->axi_clk);
> + goto dis_mg_core_clk;
> + }
> +
> + ret = clk_prepare_enable(priv->axi_clk);
> + if (ret < 0)
> + goto dis_mg_core_clk;
> +
> + return 0;
> +
> +dis_mg_core_clk:
> + clk_disable_unprepare(priv->mg_core_clk);
> +
> +dis_mg_domain_clk:
> + clk_disable_unprepare(priv->mg_domain_clk);
> +
> + priv->mg_domain_clk = NULL;
> + priv->mg_core_clk = NULL;
> + priv->axi_clk = NULL;
> +
> + return ret;
> +};
> +
> +static void mvebu_comphy_disable_unprepare_clks(struct mvebu_comphy_priv *priv)
> +{
> + if (priv->axi_clk)
> + clk_disable_unprepare(priv->axi_clk);
> +
> + if (priv->mg_core_clk)
> + clk_disable_unprepare(priv->mg_core_clk);
> +
> + if (priv->mg_domain_clk)
> + clk_disable_unprepare(priv->mg_domain_clk);
> +}
> +
> static int mvebu_comphy_probe(struct platform_device *pdev)
> {
> struct mvebu_comphy_priv *priv;
> struct phy_provider *provider;
> struct device_node *child;
> struct resource *res;
> + int ret;
>
> priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
> if (!priv)
> @@ -607,10 +671,17 @@ static int mvebu_comphy_probe(struct platform_device *pdev)
> if (IS_ERR(priv->base))
> return PTR_ERR(priv->base);
>
> + /*
> + * Ignore error if clocks have not been initialized properly for DT
> + * compatibility reasons.
> + */
> + ret = mvebu_comphy_init_clks(priv);
> + if (ret)
> + dev_warn(&pdev->dev, "cannot initialize clocks\n");
> +
Please request probe retry when clocks are not ready, e.g.:
- if (ret)
+ if (ret) {
+ if (ret == -EPROBE_DEFER)
+ return ret;
dev_warn(&pdev->dev, "cannot initialize clocks\n");
+ }
After that you can put:
Tested-by: Grzegorz Jaszczyk <jaz@semihalf.com>
regards,
Grzegorz
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox