* [PATCH V2 2/3] perf/imx_ddr: Add system PMU identifier for userspace
From: Joakim Zhang @ 2020-05-20 2:56 UTC (permalink / raw)
To: john.garry, will, mark.rutland, robh+dt, shawnguo
Cc: devicetree, linux-imx, linux-arm-kernel, linux-kernel
In-Reply-To: <20200520025619.687-1-qiangqing.zhang@nxp.com>
The DDR Perf for i.MX8 is a system PMU whose axi id would different from
SoC to SoC. Need expose system PMU identifier for userspace which refer
to /sys/bus/event_source/devices/<PMU DEVICE>/identifier.
Signed-off-by: Joakim Zhang <qiangqing.zhang@nxp.com>
---
drivers/perf/fsl_imx8_ddr_perf.c | 29 +++++++++++++++++++++++++++++
1 file changed, 29 insertions(+)
diff --git a/drivers/perf/fsl_imx8_ddr_perf.c b/drivers/perf/fsl_imx8_ddr_perf.c
index 90884d14f95f..ba523a94f4d7 100644
--- a/drivers/perf/fsl_imx8_ddr_perf.c
+++ b/drivers/perf/fsl_imx8_ddr_perf.c
@@ -76,6 +76,7 @@ struct ddr_pmu {
unsigned int cpu;
struct hlist_node node;
struct device *dev;
+ const char *identifier;
struct perf_event *events[NUM_COUNTERS];
int active_events;
enum cpuhp_state cpuhp_state;
@@ -84,6 +85,27 @@ struct ddr_pmu {
int id;
};
+static ssize_t ddr_perf_identifier_show(struct device *dev,
+ struct device_attribute *attr,
+ char *page)
+{
+ struct ddr_pmu *pmu = dev_get_drvdata(dev);
+
+ return sprintf(page, "%s\n", pmu->identifier);
+}
+
+static struct device_attribute ddr_perf_identifier_attr =
+ __ATTR(identifier, 0444, ddr_perf_identifier_show, NULL);
+
+static struct attribute *ddr_perf_identifier_attrs[] = {
+ &ddr_perf_identifier_attr.attr,
+ NULL,
+};
+
+static struct attribute_group ddr_perf_identifier_attr_group = {
+ .attrs = ddr_perf_identifier_attrs,
+};
+
enum ddr_perf_filter_capabilities {
PERF_CAP_AXI_ID_FILTER = 0,
PERF_CAP_AXI_ID_FILTER_ENHANCED,
@@ -237,6 +259,7 @@ static const struct attribute_group *attr_groups[] = {
&ddr_perf_format_attr_group,
&ddr_perf_cpumask_attr_group,
&ddr_perf_filter_cap_attr_group,
+ &ddr_perf_identifier_attr_group,
NULL,
};
@@ -601,6 +624,7 @@ static int ddr_perf_probe(struct platform_device *pdev)
struct ddr_pmu *pmu;
struct device_node *np;
void __iomem *base;
+ const char *identifier = NULL;
char *name;
int num;
int ret;
@@ -620,6 +644,11 @@ static int ddr_perf_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, pmu);
+ ret = of_property_read_string(np, "identifier", &identifier);
+ if (ret < 0)
+ dev_warn(&pdev->dev, "Failed to get identifier\n");
+ pmu->identifier = identifier;
+
name = devm_kasprintf(&pdev->dev, GFP_KERNEL, DDR_PERF_DEV_NAME "%d",
num);
if (!name)
--
2.17.1
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply related
* [PATCH V2 3/3] arm64: dts: imx8/8mm/8mn/8mq: add identifier for DDR perf
From: Joakim Zhang @ 2020-05-20 2:56 UTC (permalink / raw)
To: john.garry, will, mark.rutland, robh+dt, shawnguo
Cc: devicetree, linux-imx, linux-arm-kernel, linux-kernel
In-Reply-To: <20200520025619.687-1-qiangqing.zhang@nxp.com>
Add identifier property for DDR perf.
Signed-off-by: Joakim Zhang <qiangqing.zhang@nxp.com>
---
arch/arm64/boot/dts/freescale/imx8mm.dtsi | 1 +
arch/arm64/boot/dts/freescale/imx8mn.dtsi | 1 +
arch/arm64/boot/dts/freescale/imx8mq.dtsi | 1 +
arch/arm64/boot/dts/freescale/imx8qxp.dtsi | 1 +
4 files changed, 4 insertions(+)
diff --git a/arch/arm64/boot/dts/freescale/imx8mm.dtsi b/arch/arm64/boot/dts/freescale/imx8mm.dtsi
index 1e5e11592f7b..ee14a6ecdb93 100644
--- a/arch/arm64/boot/dts/freescale/imx8mm.dtsi
+++ b/arch/arm64/boot/dts/freescale/imx8mm.dtsi
@@ -898,6 +898,7 @@
reg = <0x3d800000 0x400000>;
interrupt-parent = <&gic>;
interrupts = <GIC_SPI 98 IRQ_TYPE_LEVEL_HIGH>;
+ identifier = "i.mx8mm";
};
};
};
diff --git a/arch/arm64/boot/dts/freescale/imx8mn.dtsi b/arch/arm64/boot/dts/freescale/imx8mn.dtsi
index a44b5438e842..b93e56ebf9a7 100644
--- a/arch/arm64/boot/dts/freescale/imx8mn.dtsi
+++ b/arch/arm64/boot/dts/freescale/imx8mn.dtsi
@@ -796,6 +796,7 @@
compatible = "fsl,imx8mn-ddr-pmu", "fsl,imx8m-ddr-pmu";
reg = <0x3d800000 0x400000>;
interrupts = <GIC_SPI 98 IRQ_TYPE_LEVEL_HIGH>;
+ identifier = "i.mx8mn";
};
};
diff --git a/arch/arm64/boot/dts/freescale/imx8mq.dtsi b/arch/arm64/boot/dts/freescale/imx8mq.dtsi
index 6a1e83922c71..38cc93af35ac 100644
--- a/arch/arm64/boot/dts/freescale/imx8mq.dtsi
+++ b/arch/arm64/boot/dts/freescale/imx8mq.dtsi
@@ -1217,6 +1217,7 @@
reg = <0x3d800000 0x400000>;
interrupt-parent = <&gic>;
interrupts = <GIC_SPI 98 IRQ_TYPE_LEVEL_HIGH>;
+ identifier = "i.mx8mq";
};
};
};
diff --git a/arch/arm64/boot/dts/freescale/imx8qxp.dtsi b/arch/arm64/boot/dts/freescale/imx8qxp.dtsi
index fb5f752b15fe..0c294b549806 100644
--- a/arch/arm64/boot/dts/freescale/imx8qxp.dtsi
+++ b/arch/arm64/boot/dts/freescale/imx8qxp.dtsi
@@ -436,6 +436,7 @@
compatible = "fsl,imx8-ddr-pmu";
reg = <0x5c020000 0x10000>;
interrupts = <GIC_SPI 131 IRQ_TYPE_LEVEL_HIGH>;
+ identifier = "i.mx8";
};
};
--
2.17.1
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply related
* RE: [PATCH 3/3] arm64: dts: imx8mp: add mu node
From: Peng Fan @ 2020-05-20 3:01 UTC (permalink / raw)
To: Fabio Estevam
Cc: Aisheng Dong,
open list:OPEN FIRMWARE AND FLATTENED DEVICE TREE BINDINGS,
Stephen Boyd, Daniel Baluta, linux-kernel, Rob Herring,
dl-linux-imx, Sascha Hauer, Fabio Estevam, Leonard Crestez,
Shawn Guo, linux-clk,
moderated list:ARM/FREESCALE IMX / MXC ARM ARCHITECTURE,
Lucas Stach
In-Reply-To: <CAOMZO5BPPRy_XGHHyZfE3eOrmCwW_VytueY-An8qqke6HU06TQ@mail.gmail.com>
> Subject: Re: [PATCH 3/3] arm64: dts: imx8mp: add mu node
>
> Hi Peng,
>
> On Tue, May 19, 2020 at 11:15 PM <peng.fan@nxp.com> wrote:
>
> > + mu: mailbox@30aa0000 {
> > + compatible = "fsl,imx6sx-mu";
>
> This should be better described as:
>
> compatible = "fsl,imx8mp-mu", "fsl,imx6sx-mu";
>
> From Documentation/devicetree/bindings/mailbox/fsl,mu.txt:
>
> "The "fsl,imx6sx-mu" compatible is seen as generic and should be included
> together with SoC specific compatible."
Nothing specific in i.MX8MP for the mu part, so do we really need
add "fsl,imx8mp-mu"?
Thanks,
Peng.
_______________________________________________
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 3/3] arm64: dts: imx8mp: add mu node
From: Fabio Estevam @ 2020-05-20 3:06 UTC (permalink / raw)
To: Peng Fan
Cc: Aisheng Dong,
open list:OPEN FIRMWARE AND FLATTENED DEVICE TREE BINDINGS,
Stephen Boyd, Daniel Baluta, linux-kernel, Rob Herring,
dl-linux-imx, Sascha Hauer, Fabio Estevam, Leonard Crestez,
Shawn Guo, linux-clk,
moderated list:ARM/FREESCALE IMX / MXC ARM ARCHITECTURE,
Lucas Stach
In-Reply-To: <DB6PR0402MB27602682E90E4CED55244BCC88B60@DB6PR0402MB2760.eurprd04.prod.outlook.com>
Hi Peng,
On Wed, May 20, 2020 at 12:01 AM Peng Fan <peng.fan@nxp.com> wrote:
> Nothing specific in i.MX8MP for the mu part, so do we really need
> add "fsl,imx8mp-mu"?
It is good practice to add a more specific option.
Let's say in future a bug is found that affects imx8mp MU, then you
could fix the MU driver and keep the dtb compatibility.
_______________________________________________
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 3/3] arm64: dts: imx8mp: add mu node
From: Peng Fan @ 2020-05-20 3:06 UTC (permalink / raw)
To: Fabio Estevam
Cc: Aisheng Dong,
open list:OPEN FIRMWARE AND FLATTENED DEVICE TREE BINDINGS,
Stephen Boyd, Daniel Baluta, linux-kernel, Rob Herring,
dl-linux-imx, Sascha Hauer, Fabio Estevam, Leonard Crestez,
Shawn Guo, linux-clk,
moderated list:ARM/FREESCALE IMX / MXC ARM ARCHITECTURE,
Lucas Stach
In-Reply-To: <CAOMZO5DmiQbfJjTLKPiv6uUNaQ8ae-0h7uOpPf2J9ZMwDoE+Eg@mail.gmail.com>
> Subject: Re: [PATCH 3/3] arm64: dts: imx8mp: add mu node
>
> Hi Peng,
>
> On Wed, May 20, 2020 at 12:01 AM Peng Fan <peng.fan@nxp.com> wrote:
>
> > Nothing specific in i.MX8MP for the mu part, so do we really need add
> > "fsl,imx8mp-mu"?
>
> It is good practice to add a more specific option.
>
> Let's say in future a bug is found that affects imx8mp MU, then you could fix
> the MU driver and keep the dtb compatibility.
Got it. Thanks for the tips.
Thanks,
Peng.
_______________________________________________
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] firmware: arm_sdei: remove unused interfaces
From: Xiongfeng Wang @ 2020-05-20 3:06 UTC (permalink / raw)
To: James Morse, Christoph Hellwig; +Cc: linux-kernel, linux-arm-kernel
In-Reply-To: <0ac1444b-bbdf-1efb-54e6-db90fe6ac707@arm.com>
Hi James,
On 2020/5/19 23:47, James Morse wrote:
> Hi Xiongfeng,
>
> On 05/05/2020 03:08, Xiongfeng Wang wrote:
>> On 2020/5/5 1:14, James Morse wrote:
>>> Hi Christoph,
>>>
>>> (CC: +Xiongfeng)
>>>
>>> Thanks for the reminder - I was just searching for who was using this.
>>
>> Thanks for CC me. We do have a driver that are using it.
>
>>> On 04/05/2020 17:42, Christoph Hellwig wrote:
>>>> The export symbols to register/unregister and enable/disable events
>>>> aren't ever used outside of arm_sdei.c, so mark them static.
>>>
>>> Xiongfeng, you have drivers using this, could they be posted upstream. Or can we stop
>>> exporting these?
>>
>> It's the SDEI Wathchdog which is used for hardlockup detection. But I wasn't
>> able to push it upstream because we have Pseudo-NMI in mainline.
>
> Hmm, that shouldn't be directly relevant, unless your SDEI watchdog is using the
> bindable-irq thing?
Yes, we are using the bindable-irq thing. It's easier for the UEFI team.
Firmware doesn't need to too much modification.
>
>
> If your firmware offers an event-id for the watchdog, please upstream the driver. Half of
> the event-id space is reserved for vendor stuff like this.
My origin thought is using a new event-id. But the firmware guys are new to SDEI
and don't know how to add a new event-id.
>
> If firmware needs to be told to re-configure the watchdog irq to make this work, then pNMI
> is a much better fit. Having firmware and linux modifying the irqchip hardware is a
> nightmare best avoided.
>
Yes, we are using the secure timer irq as the watchdog irq. So the firmware
needs to disable and enable the irq when we disable and enable the event. But
linux don't need to modify the irqchip hardware about the secure timer irq.
All works well except the kdump situation. Because in sdei_handler the secure
timer irq, which is routed to EL3, remains active. We clear the EOI when we
complete the event. So when we panic and start kdump in sdei_handler, the EL2
interrupt of the second kernel can not be taken. We add a hack to clear the EOI
before start kdump.
Yes, the pNMI is a much better fit. We don't need such a hack. But the product
department seems to have get used to the SDEI watchdog method. It works well and
they don't want much change.
Thanks,
Xiongfeng
>
>>> (they were originally added for the GHES RAS thing, but by the time it was all merged
>>> upstream, it wasn't possible to build it as a module)
>>
>> The SDEI Watchdog driver also can't be built as a module. We still need to
>> modify the origin kernel. So I think this patch doesn't affect me. Thanks for CC me.
>
> Okay, I'll pick this up to drop the module exports.
>
> I'd prefer not to make all this static as these register/unregister calls are the
> interface that is supposed to be used. If we are going to gut it, we should do it completely.
>
>
> Thanks,
>
> James
>
> .
>
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply
* [PATCH -next] bus: arm-integrator-lm: Fix return value check in integrator_ap_lm_probe()
From: Wei Yongjun @ 2020-05-20 3:21 UTC (permalink / raw)
To: Linus Walleij
Cc: kernel-janitors, Wei Yongjun, linux-kernel, linux-arm-kernel,
Hulk Robot
In case of error, the function of_find_matching_node() returns NULL
pointer not ERR_PTR(). The IS_ERR() test in the return value check
should be replaced with NULL test.
Fixes: ccea5e8a5918 ("bus: Add driver for Integrator/AP logic modules")
Reported-by: Hulk Robot <hulkci@huawei.com>
Signed-off-by: Wei Yongjun <weiyongjun1@huawei.com>
---
drivers/bus/arm-integrator-lm.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/drivers/bus/arm-integrator-lm.c b/drivers/bus/arm-integrator-lm.c
index 669ea7e1f92e..845b6c43fef8 100644
--- a/drivers/bus/arm-integrator-lm.c
+++ b/drivers/bus/arm-integrator-lm.c
@@ -78,10 +78,10 @@ static int integrator_ap_lm_probe(struct platform_device *pdev)
/* Look up the system controller */
syscon = of_find_matching_node(NULL, integrator_ap_syscon_match);
- if (IS_ERR(syscon)) {
+ if (!syscon) {
dev_err(dev,
"could not find Integrator/AP system controller\n");
- return PTR_ERR(syscon);
+ return -ENODEV;
}
map = syscon_node_to_regmap(syscon);
if (IS_ERR(map)) {
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply related
* Re: [PATCH v7 0/4] support reserving crashkernel above 4G on arm64 kdump
From: chenzhou @ 2020-05-20 3:30 UTC (permalink / raw)
To: Arnd Bergmann
Cc: Simon Horman, john.p.donnelly, Will Deacon,
open list:DOCUMENTATION, Catalin Marinas, Bhupesh Sharma, kexec,
linux-kernel@vger.kernel.org, Ingo Molnar, James Morse,
Thomas Gleixner, pkushwaha, Dave Young, Linux ARM
In-Reply-To: <CAK8P3a2VrAqefPYF2JqRjwdhgTDtORUgWgVuYxRYWqKxE3+5pA@mail.gmail.com>
Hi Arnd,
On 2020/5/19 18:21, Arnd Bergmann wrote:
> On Thu, Mar 26, 2020 at 4:10 AM Chen Zhou <chenzhou10@huawei.com> wrote:
>> Hi all,
>>
>> Friendly ping...
> I was asked about this patch series, and see that you last posted it in
> December. I think you should rebase it to linux-5.7-rc6 and post the
> entire series again to make progress, as it's unlikely that any maintainer
> would pick up the patches from last year.
>
> For the contents, everything seems reasonable to me, but I noticed that
> you are adding a property to the /chosen node without adding the
> corresponding documentation to
> Documentation/devicetree/bindings/chosen.txt
>
> Please add that, and Cc the devicetree maintainers on the updated
> patch.
>
> Arnd
Thanks for your review and comments, i will rebase it to linux-5.7-rc6 and add the
corresponding documentation.
Thanks,
Chen Zhou
>> On 2019/12/23 23:23, Chen Zhou wrote:
>>> This patch series enable reserving crashkernel above 4G in arm64.
>>>
>>> There are following issues in arm64 kdump:
>>> 1. We use crashkernel=X to reserve crashkernel below 4G, which will fail
>>> when there is no enough low memory.
>>> 2. Currently, crashkernel=Y@X can be used to reserve crashkernel above 4G,
>>> in this case, if swiotlb or DMA buffers are required, crash dump kernel
>>> will boot failure because there is no low memory available for allocation.
>>>
>>> The previous changes and discussions can be retrieved from:
>>>
>>> Changes since [v6]
>>> - Fix build errors reported by kbuild test robot.
> ...
>
> .
>
_______________________________________________
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 0/3] ARM: imx: move cpu code to drivers/soc/imx
From: Shawn Guo @ 2020-05-20 3:31 UTC (permalink / raw)
To: peng.fan
Cc: info, abel.vesa, Anson Huang, ard.biesheuvel, git, Sascha Hauer,
allison, Linux Kernel Mailing List, NXP Linux Team, Sascha Hauer,
leonard.crestez, Fabio Estevam, linux-arm-kernel
In-Reply-To: <20200520005638.GA11739@dragon>
On Wed, May 20, 2020 at 8:57 AM Shawn Guo <shawnguo@kernel.org> wrote:
>
> On Wed, Apr 29, 2020 at 05:17:20PM +0800, peng.fan@nxp.com wrote:
> > From: Peng Fan <peng.fan@nxp.com>
> >
> > V2:
> > Keep i.MX1/2/3/5 cpu type for completness
> > Correct return value in patch 1/3
> > use CONFIG_ARM to guard compile soc-imx.c in patch 3/3
> >
> > V1:
> > https://patchwork.kernel.org/cover/11433689/
> > RFC version :
> > https://patchwork.kernel.org/cover/11336433/
> >
> > Nothing changed in v1, just rename to formal patches
> >
> > Shawn,
> > The original concern has been eliminated in RFC discussion,
> > so this patchset is ready to be in next.
> > Thanks.
> >
> > Follow i.MX8, move the soc device register code to drivers/soc/imx
> > to simplify arch/arm/mach-imx/cpu.c
> >
> > I planned to use similar logic as soc-imx8m.c to restructure soc-imx.c
> > and merged the two files into one. But not sure, so still keep
> > the logic in cpu.c.
> >
> > There is one change is the platform devices are not under
> > /sys/devices/soc0 after patch 1/4. Actually ARM64 platform
> > devices are not under /sys/devices/soc0, such as i.MX8/8M.
> > So it should not hurt to let the platform devices under platform dir.
> >
> > Peng Fan (3):
> > ARM: imx: use device_initcall for imx_soc_device_init
> > ARM: imx: move cpu definitions into a header
> > soc: imx: move cpu code to drivers/soc/imx
>
> Applied all, thanks.
Unfortunately, I have to drop this, as it turns out the series needs a
rebase onto for-next. The series conflicts with 'ARM: vf610: report
soc info via soc device' there.
Shawn
_______________________________________________
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 v10] arm64: dts: qcom: sc7180: Add WCN3990 WLAN module device node
From: Sibi Sankar @ 2020-05-20 3:34 UTC (permalink / raw)
To: Rakesh Pillai
Cc: devicetree, linux-arm-msm-owner, linux-kernel, linux-arm-kernel,
linux-arm-msm
In-Reply-To: <1589914405-6674-1-git-send-email-pillair@codeaurora.org>
Hey Rakesh,
On 2020-05-20 00:23, Rakesh Pillai wrote:
> Add device node for the ath10k SNOC platform driver probe
> and add resources required for WCN3990 on sc7180 soc.
>
> Signed-off-by: Rakesh Pillai <pillair@codeaurora.org>
> ---
> Changes from v9:
> - Place the wlan_fw_mem under reserved-memory node
> ---
> arch/arm64/boot/dts/qcom/sc7180-idp.dts | 7 +++++++
> arch/arm64/boot/dts/qcom/sc7180.dtsi | 27
> +++++++++++++++++++++++++++
> 2 files changed, 34 insertions(+)
>
> diff --git a/arch/arm64/boot/dts/qcom/sc7180-idp.dts
> b/arch/arm64/boot/dts/qcom/sc7180-idp.dts
> index 4e9149d..38b102e 100644
> --- a/arch/arm64/boot/dts/qcom/sc7180-idp.dts
> +++ b/arch/arm64/boot/dts/qcom/sc7180-idp.dts
> @@ -389,6 +389,13 @@
> };
> };
>
> +&wifi {
> + status = "okay";
> + wifi-firmware {
> + iommus = <&apps_smmu 0xc2 0x1>;
> + };
> +};
> +
> /* PINCTRL - additions to nodes defined in sc7180.dtsi */
>
> &qspi_clk {
> diff --git a/arch/arm64/boot/dts/qcom/sc7180.dtsi
> b/arch/arm64/boot/dts/qcom/sc7180.dtsi
> index f1280e0..19bd7d0 100644
> --- a/arch/arm64/boot/dts/qcom/sc7180.dtsi
> +++ b/arch/arm64/boot/dts/qcom/sc7180.dtsi
> @@ -106,6 +106,11 @@
> no-map;
> };
>
> + wlan_fw_mem: memory@94100000 {
> + reg = <0 0x94100000 0 0x200000>;
> + no-map;
> + };
> +
You can skip ^^, its already
present as wlan_mem in the
board dts.
> rmtfs_mem: memory@84400000 {
> compatible = "qcom,rmtfs-mem";
> reg = <0x0 0x84400000 0x0 0x200000>;
> @@ -944,6 +949,28 @@
> };
> };
>
> + wifi: wifi@18800000 {
> + compatible = "qcom,wcn3990-wifi";
> + reg = <0 0x18800000 0 0x800000>;
> + reg-names = "membase";
> + iommus = <&apps_smmu 0xc0 0x1>;
> + interrupts =
> + <GIC_SPI 414 IRQ_TYPE_LEVEL_HIGH /* CE0 */ >,
> + <GIC_SPI 415 IRQ_TYPE_LEVEL_HIGH /* CE1 */ >,
> + <GIC_SPI 416 IRQ_TYPE_LEVEL_HIGH /* CE2 */ >,
> + <GIC_SPI 417 IRQ_TYPE_LEVEL_HIGH /* CE3 */ >,
> + <GIC_SPI 418 IRQ_TYPE_LEVEL_HIGH /* CE4 */ >,
> + <GIC_SPI 419 IRQ_TYPE_LEVEL_HIGH /* CE5 */ >,
> + <GIC_SPI 420 IRQ_TYPE_LEVEL_HIGH /* CE6 */ >,
> + <GIC_SPI 421 IRQ_TYPE_LEVEL_HIGH /* CE7 */ >,
> + <GIC_SPI 422 IRQ_TYPE_LEVEL_HIGH /* CE8 */ >,
> + <GIC_SPI 423 IRQ_TYPE_LEVEL_HIGH /* CE9 */ >,
> + <GIC_SPI 424 IRQ_TYPE_LEVEL_HIGH /* CE10 */>,
> + <GIC_SPI 425 IRQ_TYPE_LEVEL_HIGH /* CE11 */>;
> + memory-region = <&wlan_fw_mem>;
Its named as wlan_mem in sc7180-idp.dts
> + status = "disabled";
> + };
> +
> config_noc: interconnect@1500000 {
> compatible = "qcom,sc7180-config-noc";
> reg = <0 0x01500000 0 0x28000>;
--
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum,
a Linux Foundation Collaborative Project.
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply
* [PATCH 00/12] Add cpufreq and cci devfreq for mt8183, and SVS support
From: Andrew-sh.Cheng @ 2020-05-20 3:42 UTC (permalink / raw)
To: MyungJoo Ham, Kyungmin Park, Chanwoo Choi, Rob Herring,
Mark Rutland, Matthias Brugger, Rafael J . Wysocki, Viresh Kumar,
Nishanth Menon, Stephen Boyd, Liam Girdwood, Mark Brown
Cc: devicetree, Andrew-sh.Cheng, srv_heupstream, linux-pm,
linux-kernel, linux-mediatek, linux-arm-kernel
MT8183 supports CPU DVFS and CCI DVFS, and LITTLE cpus and CCI are in the same voltage domain.
So, this series is to add drivers to handle the voltage coupling between CPU and CCI DVFS.
For SVS support, need OPP_EVENT_ADJUST_VOLTAGE and corresponding reaction.
Change since v5:
- Changing dt-binding format to yaml.
- Extending current devfreq passive_governor instead of create a new one.
- Resend depending patches of Sravana Kannan base on kernel-5.7
Andrew-sh.Cheng (6):
cpufreq: mediatek: add clock and regulator enable for intermediate
clock
dt-bindings: devfreq: add compatible for mt8183 cci devfreq
devfreq: add mediatek cci devfreq
opp: Modify opp API, dev_pm_opp_get_freq(), find freq in opp, even it
is disabled
cpufreq: mediatek: add opp notification for SVS support
devfreq: mediatek: cci devfreq register opp notification for SVS
support
Saravana Kannan (6):
OPP: Allow required-opps even if the device doesn't have power-domains
OPP: Add function to look up required OPP's for a given OPP
OPP: Improve required-opps linking
PM / devfreq: Cache OPP table reference in devfreq
PM / devfreq: Add required OPPs support to passive governor
PM / devfreq: Add cpu based scaling support to passive_governor
.../devicetree/bindings/devfreq/mt8183-cci.yaml | 51 ++++
drivers/cpufreq/mediatek-cpufreq.c | 122 ++++++++-
drivers/devfreq/Kconfig | 12 +
drivers/devfreq/Makefile | 1 +
drivers/devfreq/devfreq.c | 6 +
drivers/devfreq/governor_passive.c | 298 +++++++++++++++++++--
drivers/devfreq/mt8183-cci-devfreq.c | 233 ++++++++++++++++
drivers/opp/core.c | 85 +++++-
drivers/opp/of.c | 108 ++++----
drivers/opp/opp.h | 5 +
include/linux/devfreq.h | 42 ++-
include/linux/pm_opp.h | 11 +
12 files changed, 874 insertions(+), 100 deletions(-)
create mode 100644 Documentation/devicetree/bindings/devfreq/mt8183-cci.yaml
create mode 100644 drivers/devfreq/mt8183-cci-devfreq.c
--
2.12.5
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply
* [PATCH 12/12] devfreq: mediatek: cci devfreq register opp notification for SVS support
From: Andrew-sh.Cheng @ 2020-05-20 3:43 UTC (permalink / raw)
To: MyungJoo Ham, Kyungmin Park, Chanwoo Choi, Rob Herring,
Mark Rutland, Matthias Brugger, Rafael J . Wysocki, Viresh Kumar,
Nishanth Menon, Stephen Boyd, Liam Girdwood, Mark Brown
Cc: devicetree, Andrew-sh.Cheng, srv_heupstream, linux-pm,
linux-kernel, linux-mediatek, linux-arm-kernel
In-Reply-To: <20200520034307.20435-1-andrew-sh.cheng@mediatek.com>
SVS will change the voltage of opp item.
CCI devfreq need to react to change frequency.
Signed-off-by: Andrew-sh.Cheng <andrew-sh.cheng@mediatek.com>
---
drivers/devfreq/mt8183-cci-devfreq.c | 27 +++++++++++++++++++++++++++
1 file changed, 27 insertions(+)
diff --git a/drivers/devfreq/mt8183-cci-devfreq.c b/drivers/devfreq/mt8183-cci-devfreq.c
index cd7929a83bf8..3e03c1cac1a1 100644
--- a/drivers/devfreq/mt8183-cci-devfreq.c
+++ b/drivers/devfreq/mt8183-cci-devfreq.c
@@ -23,6 +23,7 @@ struct cci_devfreq {
struct clk *cci_clk;
int old_vproc;
unsigned long old_freq;
+ struct notifier_block opp_nb;
};
static int mtk_cci_set_voltage(struct cci_devfreq *cci_df, int vproc)
@@ -91,6 +92,26 @@ static int mtk_cci_devfreq_target(struct device *dev, unsigned long *freq,
return 0;
}
+static int ccidevfreq_opp_notifier(struct notifier_block *nb,
+ unsigned long event, void *data)
+{
+ struct dev_pm_opp *opp = data;
+ struct cci_devfreq *cci_df = container_of(nb, struct cci_devfreq,
+ opp_nb);
+ unsigned long freq, volt;
+
+ if (event == OPP_EVENT_ADJUST_VOLTAGE) {
+ freq = dev_pm_opp_get_freq(opp);
+ /* current opp item is changed */
+ if (freq == cci_df->old_freq) {
+ volt = dev_pm_opp_get_voltage(opp);
+ mtk_cci_set_voltage(cci_df, volt);
+ }
+ }
+
+ return 0;
+}
+
static struct devfreq_dev_profile cci_devfreq_profile = {
.target = mtk_cci_devfreq_target,
};
@@ -100,12 +121,15 @@ static int mtk_cci_devfreq_probe(struct platform_device *pdev)
struct device *cci_dev = &pdev->dev;
struct cci_devfreq *cci_df;
struct devfreq_passive_data *passive_data;
+ struct notifier_block *opp_nb;
int ret;
cci_df = devm_kzalloc(cci_dev, sizeof(*cci_df), GFP_KERNEL);
if (!cci_df)
return -ENOMEM;
+ opp_nb = &cci_df->opp_nb;
+
cci_df->cci_clk = devm_clk_get(cci_dev, "cci_clock");
ret = PTR_ERR_OR_ZERO(cci_df->cci_clk);
if (ret) {
@@ -153,6 +177,9 @@ static int mtk_cci_devfreq_probe(struct platform_device *pdev)
return ret;
}
+ opp_nb->notifier_call = ccidevfreq_opp_notifier;
+ dev_pm_opp_register_notifier(cci_dev, opp_nb);
+
return 0;
}
--
2.12.5
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply related
* [PATCH 11/12] cpufreq: mediatek: add opp notification for SVS support
From: Andrew-sh.Cheng @ 2020-05-20 3:43 UTC (permalink / raw)
To: MyungJoo Ham, Kyungmin Park, Chanwoo Choi, Rob Herring,
Mark Rutland, Matthias Brugger, Rafael J . Wysocki, Viresh Kumar,
Nishanth Menon, Stephen Boyd, Liam Girdwood, Mark Brown
Cc: devicetree, Andrew-sh.Cheng, srv_heupstream, linux-pm,
linux-kernel, linux-mediatek, linux-arm-kernel
In-Reply-To: <20200520034307.20435-1-andrew-sh.cheng@mediatek.com>
cpufreq should listen opp notification and do proper actions
when receiving disable and voltage adjustment events,
which are triggered when SVS is enabled.
Signed-off-by: Andrew-sh.Cheng <andrew-sh.cheng@mediatek.com>
---
drivers/cpufreq/mediatek-cpufreq.c | 89 ++++++++++++++++++++++++++++++++++++--
1 file changed, 85 insertions(+), 4 deletions(-)
diff --git a/drivers/cpufreq/mediatek-cpufreq.c b/drivers/cpufreq/mediatek-cpufreq.c
index 4b479c110cc9..71395ab87ac7 100644
--- a/drivers/cpufreq/mediatek-cpufreq.c
+++ b/drivers/cpufreq/mediatek-cpufreq.c
@@ -42,6 +42,11 @@ struct mtk_cpu_dvfs_info {
struct list_head list_head;
int intermediate_voltage;
bool need_voltage_tracking;
+ struct mutex lock; /* avoid notify and policy race condition */
+ struct notifier_block opp_nb;
+ int opp_cpu;
+ unsigned long opp_freq;
+ int old_vproc;
};
static LIST_HEAD(dvfs_info_list);
@@ -192,11 +197,16 @@ static int mtk_cpufreq_voltage_tracking(struct mtk_cpu_dvfs_info *info,
static int mtk_cpufreq_set_voltage(struct mtk_cpu_dvfs_info *info, int vproc)
{
+ int ret;
+
if (info->need_voltage_tracking)
- return mtk_cpufreq_voltage_tracking(info, vproc);
+ ret = mtk_cpufreq_voltage_tracking(info, vproc);
else
- return regulator_set_voltage(info->proc_reg, vproc,
- vproc + VOLT_TOL);
+ ret = regulator_set_voltage(info->proc_reg, vproc,
+ MAX_VOLT_LIMIT);
+ if (!ret)
+ info->old_vproc = vproc;
+ return ret;
}
static int mtk_cpufreq_set_target(struct cpufreq_policy *policy,
@@ -214,7 +224,9 @@ static int mtk_cpufreq_set_target(struct cpufreq_policy *policy,
inter_vproc = info->intermediate_voltage;
old_freq_hz = clk_get_rate(cpu_clk);
- old_vproc = regulator_get_voltage(info->proc_reg);
+ old_vproc = info->old_vproc;
+ if (old_vproc == 0)
+ old_vproc = regulator_get_voltage(info->proc_reg);
if (old_vproc < 0) {
pr_err("%s: invalid Vproc value: %d\n", __func__, old_vproc);
return old_vproc;
@@ -231,6 +243,7 @@ static int mtk_cpufreq_set_target(struct cpufreq_policy *policy,
vproc = dev_pm_opp_get_voltage(opp);
dev_pm_opp_put(opp);
+ mutex_lock(&info->lock);
/*
* If the new voltage or the intermediate voltage is higher than the
* current voltage, scale up voltage first.
@@ -242,6 +255,7 @@ static int mtk_cpufreq_set_target(struct cpufreq_policy *policy,
pr_err("cpu%d: failed to scale up voltage!\n",
policy->cpu);
mtk_cpufreq_set_voltage(info, old_vproc);
+ mutex_unlock(&info->lock);
return ret;
}
}
@@ -253,6 +267,7 @@ static int mtk_cpufreq_set_target(struct cpufreq_policy *policy,
policy->cpu);
mtk_cpufreq_set_voltage(info, old_vproc);
WARN_ON(1);
+ mutex_unlock(&info->lock);
return ret;
}
@@ -263,6 +278,7 @@ static int mtk_cpufreq_set_target(struct cpufreq_policy *policy,
policy->cpu);
clk_set_parent(cpu_clk, armpll);
mtk_cpufreq_set_voltage(info, old_vproc);
+ mutex_unlock(&info->lock);
return ret;
}
@@ -273,6 +289,7 @@ static int mtk_cpufreq_set_target(struct cpufreq_policy *policy,
policy->cpu);
mtk_cpufreq_set_voltage(info, inter_vproc);
WARN_ON(1);
+ mutex_unlock(&info->lock);
return ret;
}
@@ -288,15 +305,69 @@ static int mtk_cpufreq_set_target(struct cpufreq_policy *policy,
clk_set_parent(cpu_clk, info->inter_clk);
clk_set_rate(armpll, old_freq_hz);
clk_set_parent(cpu_clk, armpll);
+ mutex_unlock(&info->lock);
return ret;
}
}
+ info->opp_freq = freq_hz;
+ mutex_unlock(&info->lock);
+
return 0;
}
#define DYNAMIC_POWER "dynamic-power-coefficient"
+static int mtk_cpufreq_opp_notifier(struct notifier_block *nb,
+ unsigned long event, void *data)
+{
+ struct dev_pm_opp *opp = data;
+ struct dev_pm_opp *new_opp;
+ struct mtk_cpu_dvfs_info *info;
+ unsigned long freq, volt;
+ struct cpufreq_policy *policy;
+ int ret = 0;
+
+ info = container_of(nb, struct mtk_cpu_dvfs_info, opp_nb);
+
+ if (event == OPP_EVENT_ADJUST_VOLTAGE) {
+ freq = dev_pm_opp_get_freq(opp);
+
+ mutex_lock(&info->lock);
+ if (info->opp_freq == freq) {
+ volt = dev_pm_opp_get_voltage(opp);
+ ret = mtk_cpufreq_set_voltage(info, volt);
+ if (ret)
+ dev_err(info->cpu_dev, "failed to scale voltage: %d\n",
+ ret);
+ }
+ mutex_unlock(&info->lock);
+ } else if (event == OPP_EVENT_DISABLE) {
+ freq = dev_pm_opp_get_freq(opp);
+ /* case of current opp item is disabled */
+ if (info->opp_freq == freq) {
+ freq = 1;
+ new_opp = dev_pm_opp_find_freq_ceil(info->cpu_dev,
+ &freq);
+ if (!IS_ERR(new_opp)) {
+ dev_pm_opp_put(new_opp);
+ policy = cpufreq_cpu_get(info->opp_cpu);
+ if (policy) {
+ cpufreq_driver_target(policy,
+ freq / 1000,
+ CPUFREQ_RELATION_L);
+ cpufreq_cpu_put(policy);
+ }
+ } else {
+ pr_err("%s: all opp items are disabled\n",
+ __func__);
+ }
+ }
+ }
+
+ return notifier_from_errno(ret);
+}
+
static int mtk_cpu_dvfs_info_init(struct mtk_cpu_dvfs_info *info, int cpu)
{
struct device *cpu_dev;
@@ -392,11 +463,21 @@ static int mtk_cpu_dvfs_info_init(struct mtk_cpu_dvfs_info *info, int cpu)
info->intermediate_voltage = dev_pm_opp_get_voltage(opp);
dev_pm_opp_put(opp);
+ info->opp_cpu = cpu;
+ info->opp_nb.notifier_call = mtk_cpufreq_opp_notifier;
+ ret = dev_pm_opp_register_notifier(cpu_dev, &info->opp_nb);
+ if (ret) {
+ pr_warn("cannot register opp notification\n");
+ goto out_disable_inter_clock;
+ }
+
+ mutex_init(&info->lock);
info->cpu_dev = cpu_dev;
info->proc_reg = proc_reg;
info->sram_reg = IS_ERR(sram_reg) ? NULL : sram_reg;
info->cpu_clk = cpu_clk;
info->inter_clk = inter_clk;
+ info->opp_freq = clk_get_rate(cpu_clk);
/*
* If SRAM regulator is present, software "voltage tracking" is needed
--
2.12.5
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply related
* [PATCH 01/12] OPP: Allow required-opps even if the device doesn't have power-domains
From: Andrew-sh.Cheng @ 2020-05-20 3:42 UTC (permalink / raw)
To: MyungJoo Ham, Kyungmin Park, Chanwoo Choi, Rob Herring,
Mark Rutland, Matthias Brugger, Rafael J . Wysocki, Viresh Kumar,
Nishanth Menon, Stephen Boyd, Liam Girdwood, Mark Brown
Cc: devicetree, Saravana Kannan, srv_heupstream, linux-pm,
linux-kernel, linux-mediatek, linux-arm-kernel
In-Reply-To: <20200520034307.20435-1-andrew-sh.cheng@mediatek.com>
From: Saravana Kannan <saravanak@google.com>
A Device-A can have a (minimum) performance requirement on another
Device-B to be able to function correctly. This performance requirement
on Device-B can also change based on the current performance level of
Device-A.
The existing required-opps feature fits well to describe this need. So,
instead of limiting required-opps to point to only PM-domain devices,
allow it to point to any device.
Signed-off-by: Saravana Kannan <saravanak@google.com>
---
drivers/opp/core.c | 2 +-
drivers/opp/of.c | 11 -----------
2 files changed, 1 insertion(+), 12 deletions(-)
diff --git a/drivers/opp/core.c b/drivers/opp/core.c
index ba43e6a3dc0a..51403c1f2481 100644
--- a/drivers/opp/core.c
+++ b/drivers/opp/core.c
@@ -755,7 +755,7 @@ static int _set_required_opps(struct device *dev,
return 0;
/* Single genpd case */
- if (!genpd_virt_devs) {
+ if (!genpd_virt_devs && required_opp_tables[0]->is_genpd) {
pstate = likely(opp) ? opp->required_opps[0]->pstate : 0;
ret = dev_pm_genpd_set_performance_state(dev, pstate);
if (ret) {
diff --git a/drivers/opp/of.c b/drivers/opp/of.c
index 9cd8f0adacae..6d33de668a7b 100644
--- a/drivers/opp/of.c
+++ b/drivers/opp/of.c
@@ -195,17 +195,6 @@ static void _opp_table_alloc_required_tables(struct opp_table *opp_table,
if (IS_ERR(required_opp_tables[i]))
goto free_required_tables;
-
- /*
- * We only support genpd's OPPs in the "required-opps" for now,
- * as we don't know how much about other cases. Error out if the
- * required OPP doesn't belong to a genpd.
- */
- if (!required_opp_tables[i]->is_genpd) {
- dev_err(dev, "required-opp doesn't belong to genpd: %pOF\n",
- required_np);
- goto free_required_tables;
- }
}
goto put_np;
--
2.12.5
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply related
* [PATCH 02/12] OPP: Add function to look up required OPP's for a given OPP
From: Andrew-sh.Cheng @ 2020-05-20 3:42 UTC (permalink / raw)
To: MyungJoo Ham, Kyungmin Park, Chanwoo Choi, Rob Herring,
Mark Rutland, Matthias Brugger, Rafael J . Wysocki, Viresh Kumar,
Nishanth Menon, Stephen Boyd, Liam Girdwood, Mark Brown
Cc: devicetree, Saravana Kannan, srv_heupstream, linux-pm,
linux-kernel, linux-mediatek, linux-arm-kernel
In-Reply-To: <20200520034307.20435-1-andrew-sh.cheng@mediatek.com>
From: Saravana Kannan <saravanak@google.com>
Add a function that allows looking up required OPPs given a source OPP
table, destination OPP table and the source OPP.
Signed-off-by: Saravana Kannan <saravanak@google.com>
---
drivers/opp/core.c | 53 ++++++++++++++++++++++++++++++++++++++++++++++++++
include/linux/pm_opp.h | 11 +++++++++++
2 files changed, 64 insertions(+)
diff --git a/drivers/opp/core.c b/drivers/opp/core.c
index 51403c1f2481..64666d3eaf5b 100644
--- a/drivers/opp/core.c
+++ b/drivers/opp/core.c
@@ -1923,6 +1923,59 @@ void dev_pm_opp_detach_genpd(struct opp_table *opp_table)
EXPORT_SYMBOL_GPL(dev_pm_opp_detach_genpd);
/**
+ * dev_pm_opp_xlate_required_opp() - Find required OPP for @src_table OPP.
+ * @src_table: OPP table which has @dst_table as one of its required OPP table.
+ * @dst_table: Required OPP table of the @src_table.
+ *
+ * This function returns the OPP (present in @dst_table) pointed out by the
+ * "required-opps" property of the OPP (present in @src_table).
+ *
+ * The callers are required to call dev_pm_opp_put() for the returned OPP after
+ * use.
+ *
+ * Return: destination table OPP on success, otherwise NULL on errors.
+ */
+struct dev_pm_opp *dev_pm_opp_xlate_required_opp(struct opp_table *src_table,
+ struct opp_table *dst_table,
+ struct dev_pm_opp *src_opp)
+{
+ struct dev_pm_opp *opp, *dest_opp = NULL;
+ int i;
+
+ if (!src_table || !dst_table || !src_opp)
+ return NULL;
+
+ for (i = 0; i < src_table->required_opp_count; i++) {
+ if (src_table->required_opp_tables[i]->np == dst_table->np)
+ break;
+ }
+
+ if (unlikely(i == src_table->required_opp_count)) {
+ pr_err("%s: Couldn't find matching OPP table (%p: %p)\n",
+ __func__, src_table, dst_table);
+ return NULL;
+ }
+
+ mutex_lock(&src_table->lock);
+
+ list_for_each_entry(opp, &src_table->opp_list, node) {
+ if (opp == src_opp) {
+ dest_opp = opp->required_opps[i];
+ dev_pm_opp_get(dest_opp);
+ goto unlock;
+ }
+ }
+
+ pr_err("%s: Couldn't find matching OPP (%p: %p)\n", __func__, src_table,
+ dst_table);
+
+unlock:
+ mutex_unlock(&src_table->lock);
+
+ return dest_opp;
+}
+
+/**
* dev_pm_opp_xlate_performance_state() - Find required OPP's pstate for src_table.
* @src_table: OPP table which has dst_table as one of its required OPP table.
* @dst_table: Required OPP table of the src_table.
diff --git a/include/linux/pm_opp.h b/include/linux/pm_opp.h
index 747861816f4f..909cf7563d35 100644
--- a/include/linux/pm_opp.h
+++ b/include/linux/pm_opp.h
@@ -137,6 +137,9 @@ struct opp_table *dev_pm_opp_register_set_opp_helper(struct device *dev, int (*s
void dev_pm_opp_unregister_set_opp_helper(struct opp_table *opp_table);
struct opp_table *dev_pm_opp_attach_genpd(struct device *dev, const char **names, struct device ***virt_devs);
void dev_pm_opp_detach_genpd(struct opp_table *opp_table);
+struct dev_pm_opp *dev_pm_opp_xlate_required_opp(struct opp_table *src_table,
+ struct opp_table *dst_table,
+ struct dev_pm_opp *src_opp);
int dev_pm_opp_xlate_performance_state(struct opp_table *src_table, struct opp_table *dst_table, unsigned int pstate);
int dev_pm_opp_set_rate(struct device *dev, unsigned long target_freq);
int dev_pm_opp_set_sharing_cpus(struct device *cpu_dev, const struct cpumask *cpumask);
@@ -320,6 +323,14 @@ static inline struct opp_table *dev_pm_opp_attach_genpd(struct device *dev, cons
static inline void dev_pm_opp_detach_genpd(struct opp_table *opp_table) {}
+static inline struct dev_pm_opp *dev_pm_opp_xlate_required_opp(
+ struct opp_table *src_table,
+ struct opp_table *dst_table,
+ struct dev_pm_opp *src_opp)
+{
+ return NULL;
+}
+
static inline int dev_pm_opp_xlate_performance_state(struct opp_table *src_table, struct opp_table *dst_table, unsigned int pstate)
{
return -ENOTSUPP;
--
2.12.5
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply related
* [PATCH 09/12] devfreq: add mediatek cci devfreq
From: Andrew-sh.Cheng @ 2020-05-20 3:43 UTC (permalink / raw)
To: MyungJoo Ham, Kyungmin Park, Chanwoo Choi, Rob Herring,
Mark Rutland, Matthias Brugger, Rafael J . Wysocki, Viresh Kumar,
Nishanth Menon, Stephen Boyd, Liam Girdwood, Mark Brown
Cc: devicetree, Andrew-sh.Cheng, srv_heupstream, linux-pm,
linux-kernel, linux-mediatek, linux-arm-kernel
In-Reply-To: <20200520034307.20435-1-andrew-sh.cheng@mediatek.com>
This adds a devfreq driver for the Cache Coherent Interconnect (CCI)
of the Mediatek MT8183.
On the MT8183 the CCI is supplied by the same regulator as the LITTLE
cores. The driver is notified when the regulator voltage changes
(driven by cpufreq) and adjusts the CCI frequency to the maximum
possible value.
Signed-off-by: Andrew-sh.Cheng <andrew-sh.cheng@mediatek.com>
---
drivers/devfreq/Kconfig | 10 ++
drivers/devfreq/Makefile | 1 +
drivers/devfreq/mt8183-cci-devfreq.c | 206 +++++++++++++++++++++++++++++++++++
3 files changed, 217 insertions(+)
create mode 100644 drivers/devfreq/mt8183-cci-devfreq.c
diff --git a/drivers/devfreq/Kconfig b/drivers/devfreq/Kconfig
index d9067950af6a..4ed7116271ee 100644
--- a/drivers/devfreq/Kconfig
+++ b/drivers/devfreq/Kconfig
@@ -103,6 +103,16 @@ config ARM_IMX8M_DDRC_DEVFREQ
This adds the DEVFREQ driver for the i.MX8M DDR Controller. It allows
adjusting DRAM frequency.
+config ARM_MT8183_CCI_DEVFREQ
+ tristate "MT8183 CCI DEVFREQ Driver"
+ depends on ARM_MEDIATEK_CPUFREQ
+ help
+ This adds a devfreq driver for Cache Coherent Interconnect
+ of Mediatek MT8183, which is shared the same regulator
+ with cpu cluster.
+ It can track buck voltage and update a proper cci frequency.
+ Use notification to get regulator status.
+
config ARM_TEGRA_DEVFREQ
tristate "NVIDIA Tegra30/114/124/210 DEVFREQ Driver"
depends on ARCH_TEGRA_3x_SOC || ARCH_TEGRA_114_SOC || \
diff --git a/drivers/devfreq/Makefile b/drivers/devfreq/Makefile
index 3eb4d5e6635c..5b1b670c954d 100644
--- a/drivers/devfreq/Makefile
+++ b/drivers/devfreq/Makefile
@@ -10,6 +10,7 @@ obj-$(CONFIG_DEVFREQ_GOV_PASSIVE) += governor_passive.o
# DEVFREQ Drivers
obj-$(CONFIG_ARM_EXYNOS_BUS_DEVFREQ) += exynos-bus.o
obj-$(CONFIG_ARM_IMX8M_DDRC_DEVFREQ) += imx8m-ddrc.o
+obj-$(CONFIG_ARM_MT8183_CCI_DEVFREQ) += mt8183-cci-devfreq.o
obj-$(CONFIG_ARM_RK3399_DMC_DEVFREQ) += rk3399_dmc.o
obj-$(CONFIG_ARM_TEGRA_DEVFREQ) += tegra30-devfreq.o
obj-$(CONFIG_ARM_TEGRA20_DEVFREQ) += tegra20-devfreq.o
diff --git a/drivers/devfreq/mt8183-cci-devfreq.c b/drivers/devfreq/mt8183-cci-devfreq.c
new file mode 100644
index 000000000000..cd7929a83bf8
--- /dev/null
+++ b/drivers/devfreq/mt8183-cci-devfreq.c
@@ -0,0 +1,206 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2019 MediaTek Inc.
+
+ * Author: Andrew-sh.Cheng <andrew-sh.cheng@mediatek.com>
+ */
+
+#include <linux/clk.h>
+#include <linux/devfreq.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/regulator/consumer.h>
+#include <linux/time.h>
+
+#include "governor.h"
+
+#define MAX_VOLT_LIMIT (1150000)
+
+struct cci_devfreq {
+ struct devfreq *devfreq;
+ struct regulator *proc_reg;
+ struct clk *cci_clk;
+ int old_vproc;
+ unsigned long old_freq;
+};
+
+static int mtk_cci_set_voltage(struct cci_devfreq *cci_df, int vproc)
+{
+ int ret;
+
+ ret = regulator_set_voltage(cci_df->proc_reg, vproc,
+ MAX_VOLT_LIMIT);
+ if (!ret)
+ cci_df->old_vproc = vproc;
+ return ret;
+}
+
+static int mtk_cci_devfreq_target(struct device *dev, unsigned long *freq,
+ u32 flags)
+{
+ int ret;
+ struct cci_devfreq *cci_df = dev_get_drvdata(dev);
+ struct dev_pm_opp *opp;
+ unsigned long opp_rate, opp_voltage, old_voltage;
+
+ if (!cci_df)
+ return -EINVAL;
+
+ if (cci_df->old_freq == *freq)
+ return 0;
+
+ opp_rate = *freq;
+ opp = dev_pm_opp_find_freq_floor(dev, &opp_rate);
+ opp_voltage = dev_pm_opp_get_voltage(opp);
+ dev_pm_opp_put(opp);
+
+ old_voltage = cci_df->old_vproc;
+ if (old_voltage == 0)
+ old_voltage = regulator_get_voltage(cci_df->proc_reg);
+
+ // scale up: set voltage first then freq
+ if (opp_voltage > old_voltage) {
+ ret = mtk_cci_set_voltage(cci_df, opp_voltage);
+ if (ret) {
+ pr_err("cci: failed to scale up voltage\n");
+ return ret;
+ }
+ }
+
+ ret = clk_set_rate(cci_df->cci_clk, *freq);
+ if (ret) {
+ pr_err("%s: failed cci to set rate: %d\n", __func__,
+ ret);
+ mtk_cci_set_voltage(cci_df, old_voltage);
+ return ret;
+ }
+
+ // scale down: set freq first then voltage
+ if (opp_voltage < old_voltage) {
+ ret = mtk_cci_set_voltage(cci_df, opp_voltage);
+ if (ret) {
+ pr_err("cci: failed to scale down voltage\n");
+ clk_set_rate(cci_df->cci_clk, cci_df->old_freq);
+ return ret;
+ }
+ }
+
+ cci_df->old_freq = *freq;
+
+ return 0;
+}
+
+static struct devfreq_dev_profile cci_devfreq_profile = {
+ .target = mtk_cci_devfreq_target,
+};
+
+static int mtk_cci_devfreq_probe(struct platform_device *pdev)
+{
+ struct device *cci_dev = &pdev->dev;
+ struct cci_devfreq *cci_df;
+ struct devfreq_passive_data *passive_data;
+ int ret;
+
+ cci_df = devm_kzalloc(cci_dev, sizeof(*cci_df), GFP_KERNEL);
+ if (!cci_df)
+ return -ENOMEM;
+
+ cci_df->cci_clk = devm_clk_get(cci_dev, "cci_clock");
+ ret = PTR_ERR_OR_ZERO(cci_df->cci_clk);
+ if (ret) {
+ if (ret != -EPROBE_DEFER)
+ dev_err(cci_dev, "failed to get clock for CCI: %d\n",
+ ret);
+ return ret;
+ }
+ cci_df->proc_reg = devm_regulator_get_optional(cci_dev, "proc");
+ ret = PTR_ERR_OR_ZERO(cci_df->proc_reg);
+ if (ret) {
+ if (ret != -EPROBE_DEFER)
+ dev_err(cci_dev, "failed to get regulator for CCI: %d\n",
+ ret);
+ return ret;
+ }
+ ret = regulator_enable(cci_df->proc_reg);
+ if (ret) {
+ pr_warn("enable buck for cci fail\n");
+ return ret;
+ }
+
+ ret = dev_pm_opp_of_add_table(cci_dev);
+ if (ret) {
+ dev_err(cci_dev, "Fail to init CCI OPP table: %d\n", ret);
+ return ret;
+ }
+
+ platform_set_drvdata(pdev, cci_df);
+
+ passive_data = devm_kzalloc(cci_dev, sizeof(*passive_data), GFP_KERNEL);
+ if (!passive_data)
+ return -ENOMEM;
+
+ passive_data->parent_type = CPUFREQ_PARENT_DEV;
+
+ cci_df->devfreq = devm_devfreq_add_device(cci_dev,
+ &cci_devfreq_profile,
+ DEVFREQ_GOV_PASSIVE,
+ passive_data);
+ if (IS_ERR(cci_df->devfreq)) {
+ ret = PTR_ERR(cci_df->devfreq);
+ dev_err(cci_dev, "cannot create cci devfreq device:%d\n", ret);
+ dev_pm_opp_of_remove_table(cci_dev);
+ return ret;
+ }
+
+ return 0;
+}
+
+static int mtk_cci_devfreq_remove(struct platform_device *pdev)
+{
+ struct device *cci_dev = &pdev->dev;
+ struct cci_devfreq *cci_df;
+ struct notifier_block *opp_nb;
+
+ cci_df = platform_get_drvdata(pdev);
+ opp_nb = &cci_df->opp_nb;
+
+ dev_pm_opp_unregister_notifier(cci_dev, opp_nb);
+ devm_devfreq_remove_device(cci_dev, cci_df->devfreq);
+ dev_pm_opp_of_remove_table(cci_dev);
+ regulator_disable(cci_df->proc_reg);
+
+ return 0;
+}
+
+static const __maybe_unused struct of_device_id
+ mediatek_cci_devfreq_of_match[] = {
+ { .compatible = "mediatek,mt8183-cci" },
+ { },
+};
+MODULE_DEVICE_TABLE(of, mediatek_cci_devfreq_of_match);
+
+static struct platform_driver cci_devfreq_driver = {
+ .probe = mtk_cci_devfreq_probe,
+ .remove = mtk_cci_devfreq_remove,
+ .driver = {
+ .name = "mediatek-cci-devfreq",
+ .of_match_table = of_match_ptr(mediatek_cci_devfreq_of_match),
+ },
+};
+
+static int __init mtk_cci_devfreq_init(void)
+{
+ return platform_driver_register(&cci_devfreq_driver);
+}
+module_init(mtk_cci_devfreq_init)
+
+static void __exit mtk_cci_devfreq_exit(void)
+{
+ platform_driver_unregister(&cci_devfreq_driver);
+}
+module_exit(mtk_cci_devfreq_exit)
+
+MODULE_DESCRIPTION("Mediatek CCI devfreq driver");
+MODULE_AUTHOR("Andrew-sh.Cheng <andrew-sh.cheng@mediatek.com>");
+MODULE_LICENSE("GPL v2");
--
2.12.5
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply related
* [PATCH 03/12] OPP: Improve required-opps linking
From: Andrew-sh.Cheng @ 2020-05-20 3:42 UTC (permalink / raw)
To: MyungJoo Ham, Kyungmin Park, Chanwoo Choi, Rob Herring,
Mark Rutland, Matthias Brugger, Rafael J . Wysocki, Viresh Kumar,
Nishanth Menon, Stephen Boyd, Liam Girdwood, Mark Brown
Cc: devicetree, Saravana Kannan, srv_heupstream, linux-pm,
linux-kernel, linux-mediatek, linux-arm-kernel
In-Reply-To: <20200520034307.20435-1-andrew-sh.cheng@mediatek.com>
From: Saravana Kannan <saravanak@google.com>
Currently, the linking of required-opps fails silently if the
destination OPP table hasn't been added before the source OPP table is
added. This puts an unnecessary requirement that the destination table
be added before the source table is added.
In reality, the destination table is needed only when we try to
translate from source OPP to destination OPP. So, instead of
completely failing, retry linking the tables when the translation is
attempted.
Signed-off-by: Saravana Kannan <saravanak@google.com>
---
drivers/opp/core.c | 30 +++++++++++-----
drivers/opp/of.c | 101 ++++++++++++++++++++++++++++-------------------------
drivers/opp/opp.h | 5 +++
3 files changed, 80 insertions(+), 56 deletions(-)
diff --git a/drivers/opp/core.c b/drivers/opp/core.c
index 64666d3eaf5b..284b01223831 100644
--- a/drivers/opp/core.c
+++ b/drivers/opp/core.c
@@ -754,6 +754,9 @@ static int _set_required_opps(struct device *dev,
if (!required_opp_tables)
return 0;
+ if (!_of_lazy_link_required_tables(opp_table))
+ return -EPROBE_DEFER;
+
/* Single genpd case */
if (!genpd_virt_devs && required_opp_tables[0]->is_genpd) {
pstate = likely(opp) ? opp->required_opps[0]->pstate : 0;
@@ -774,11 +777,16 @@ static int _set_required_opps(struct device *dev,
mutex_lock(&opp_table->genpd_virt_dev_lock);
for (i = 0; i < opp_table->required_opp_count; i++) {
- pstate = likely(opp) ? opp->required_opps[i]->pstate : 0;
-
if (!genpd_virt_devs[i])
continue;
+ if (!opp->required_opps[i]) {
+ ret = -ENODEV;
+ break;
+ }
+
+ pstate = likely(opp) ? opp->required_opps[i]->pstate : 0;
+
ret = dev_pm_genpd_set_performance_state(genpd_virt_devs[i], pstate);
if (ret) {
dev_err(dev, "Failed to set performance rate of %s: %d (%d)\n",
@@ -1945,8 +1953,11 @@ struct dev_pm_opp *dev_pm_opp_xlate_required_opp(struct opp_table *src_table,
if (!src_table || !dst_table || !src_opp)
return NULL;
+ _of_lazy_link_required_tables(src_table);
+
for (i = 0; i < src_table->required_opp_count; i++) {
- if (src_table->required_opp_tables[i]->np == dst_table->np)
+ if (src_table->required_opp_tables[i]
+ && src_table->required_opp_tables[i]->np == dst_table->np)
break;
}
@@ -2009,6 +2020,8 @@ int dev_pm_opp_xlate_performance_state(struct opp_table *src_table,
if (!src_table->required_opp_count)
return pstate;
+ _of_lazy_link_required_tables(src_table);
+
for (i = 0; i < src_table->required_opp_count; i++) {
if (src_table->required_opp_tables[i]->np == dst_table->np)
break;
@@ -2024,15 +2037,16 @@ int dev_pm_opp_xlate_performance_state(struct opp_table *src_table,
list_for_each_entry(opp, &src_table->opp_list, node) {
if (opp->pstate == pstate) {
- dest_pstate = opp->required_opps[i]->pstate;
- goto unlock;
+ if (opp->required_opps[i])
+ dest_pstate = opp->required_opps[i]->pstate;
+ break;
}
}
- pr_err("%s: Couldn't find matching OPP (%p: %p)\n", __func__, src_table,
- dst_table);
+ if (dest_pstate < 0)
+ pr_err("%s: Couldn't find matching OPP (%p: %p)\n", __func__,
+ src_table, dst_table);
-unlock:
mutex_unlock(&src_table->lock);
return dest_pstate;
diff --git a/drivers/opp/of.c b/drivers/opp/of.c
index 6d33de668a7b..c6b1c317e4f7 100644
--- a/drivers/opp/of.c
+++ b/drivers/opp/of.c
@@ -143,7 +143,7 @@ static void _opp_table_free_required_tables(struct opp_table *opp_table)
for (i = 0; i < opp_table->required_opp_count; i++) {
if (IS_ERR_OR_NULL(required_opp_tables[i]))
- break;
+ continue;
dev_pm_opp_put_opp_table(required_opp_tables[i]);
}
@@ -163,8 +163,8 @@ static void _opp_table_alloc_required_tables(struct opp_table *opp_table,
struct device_node *opp_np)
{
struct opp_table **required_opp_tables;
- struct device_node *required_np, *np;
- int count, i;
+ struct device_node *np;
+ int count;
/* Traversing the first OPP node is all we need */
np = of_get_next_available_child(opp_np, NULL);
@@ -174,35 +174,65 @@ static void _opp_table_alloc_required_tables(struct opp_table *opp_table,
}
count = of_count_phandle_with_args(np, "required-opps", NULL);
+ of_node_put(np);
if (!count)
- goto put_np;
+ return;
required_opp_tables = kcalloc(count, sizeof(*required_opp_tables),
GFP_KERNEL);
if (!required_opp_tables)
- goto put_np;
+ return;
opp_table->required_opp_tables = required_opp_tables;
opp_table->required_opp_count = count;
+}
+
+/*
+ * Try to link all required tables and return true if all of them have been
+ * linked. Otherwise, return false.
+ */
+bool _of_lazy_link_required_tables(struct opp_table *src)
+{
+ struct dev_pm_opp *src_opp, *tmp_opp;
+ struct opp_table *req_table;
+ struct device_node *req_np;
+ int i, num_linked = 0;
- for (i = 0; i < count; i++) {
- required_np = of_parse_required_opp(np, i);
- if (!required_np)
- goto free_required_tables;
+ mutex_lock(&src->lock);
- required_opp_tables[i] = _find_table_of_opp_np(required_np);
- of_node_put(required_np);
+ if (list_empty(&src->opp_list))
+ goto out;
- if (IS_ERR(required_opp_tables[i]))
- goto free_required_tables;
- }
+ src_opp = list_first_entry(&src->opp_list, struct dev_pm_opp, node);
- goto put_np;
+ for (i = 0; i < src->required_opp_count; i++) {
+ if (src->required_opp_tables[i]) {
+ num_linked++;
+ continue;
+ }
-free_required_tables:
- _opp_table_free_required_tables(opp_table);
-put_np:
- of_node_put(np);
+ req_np = of_parse_required_opp(src_opp->np, i);
+ if (!req_np)
+ continue;
+
+ req_table = _find_table_of_opp_np(req_np);
+ of_node_put(req_np);
+ if (!req_table)
+ continue;
+
+ src->required_opp_tables[i] = req_table;
+ list_for_each_entry(tmp_opp, &src->opp_list, node) {
+ req_np = of_parse_required_opp(tmp_opp->np, i);
+ tmp_opp->required_opps[i] = _find_opp_of_np(req_table,
+ req_np);
+ of_node_put(req_np);
+ }
+ num_linked++;
+ }
+
+out:
+ mutex_unlock(&src->lock);
+ return num_linked == src->required_opp_count;
}
void _of_init_opp_table(struct opp_table *opp_table, struct device *dev,
@@ -265,7 +295,7 @@ void _of_opp_free_required_opps(struct opp_table *opp_table,
for (i = 0; i < opp_table->required_opp_count; i++) {
if (!required_opps[i])
- break;
+ continue;
/* Put the reference back */
dev_pm_opp_put(required_opps[i]);
@@ -280,9 +310,7 @@ static int _of_opp_alloc_required_opps(struct opp_table *opp_table,
struct dev_pm_opp *opp)
{
struct dev_pm_opp **required_opps;
- struct opp_table *required_table;
- struct device_node *np;
- int i, ret, count = opp_table->required_opp_count;
+ int count = opp_table->required_opp_count;
if (!count)
return 0;
@@ -293,32 +321,7 @@ static int _of_opp_alloc_required_opps(struct opp_table *opp_table,
opp->required_opps = required_opps;
- for (i = 0; i < count; i++) {
- required_table = opp_table->required_opp_tables[i];
-
- np = of_parse_required_opp(opp->np, i);
- if (unlikely(!np)) {
- ret = -ENODEV;
- goto free_required_opps;
- }
-
- required_opps[i] = _find_opp_of_np(required_table, np);
- of_node_put(np);
-
- if (!required_opps[i]) {
- pr_err("%s: Unable to find required OPP node: %pOF (%d)\n",
- __func__, opp->np, i);
- ret = -ENODEV;
- goto free_required_opps;
- }
- }
-
return 0;
-
-free_required_opps:
- _of_opp_free_required_opps(opp_table, opp);
-
- return ret;
}
static bool _opp_is_supported(struct device *dev, struct opp_table *opp_table,
@@ -691,6 +694,8 @@ static int _of_add_opp_table_v2(struct device *dev, struct opp_table *opp_table)
if (pstate_count)
opp_table->genpd_performance_state = true;
+ _of_lazy_link_required_tables(opp_table);
+
return 0;
remove_static_opp:
diff --git a/drivers/opp/opp.h b/drivers/opp/opp.h
index d14e27102730..6a679e7f3639 100644
--- a/drivers/opp/opp.h
+++ b/drivers/opp/opp.h
@@ -221,12 +221,17 @@ void _put_opp_list_kref(struct opp_table *opp_table);
void _of_init_opp_table(struct opp_table *opp_table, struct device *dev, int index);
void _of_clear_opp_table(struct opp_table *opp_table);
struct opp_table *_managed_opp(struct device *dev, int index);
+bool _of_lazy_link_required_tables(struct opp_table *src);
void _of_opp_free_required_opps(struct opp_table *opp_table,
struct dev_pm_opp *opp);
#else
static inline void _of_init_opp_table(struct opp_table *opp_table, struct device *dev, int index) {}
static inline void _of_clear_opp_table(struct opp_table *opp_table) {}
static inline struct opp_table *_managed_opp(struct device *dev, int index) { return NULL; }
+bool _of_lazy_link_required_tables(struct opp_table *src)
+{
+ return true;
+}
static inline void _of_opp_free_required_opps(struct opp_table *opp_table,
struct dev_pm_opp *opp) {}
#endif
--
2.12.5
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply related
* [PATCH 04/12] PM / devfreq: Cache OPP table reference in devfreq
From: Andrew-sh.Cheng @ 2020-05-20 3:42 UTC (permalink / raw)
To: MyungJoo Ham, Kyungmin Park, Chanwoo Choi, Rob Herring,
Mark Rutland, Matthias Brugger, Rafael J . Wysocki, Viresh Kumar,
Nishanth Menon, Stephen Boyd, Liam Girdwood, Mark Brown
Cc: devicetree, Saravana Kannan, srv_heupstream, linux-pm,
linux-kernel, linux-mediatek, linux-arm-kernel
In-Reply-To: <20200520034307.20435-1-andrew-sh.cheng@mediatek.com>
From: Saravana Kannan <saravanak@google.com>
The OPP table can be used often in devfreq. Trying to get it each time can
be expensive, so cache it in the devfreq struct.
Signed-off-by: Saravana Kannan <saravanak@google.com>
Reviewed-by: Chanwoo Choi <cw00.choi@samsung.com>
Acked-by: MyungJoo Ham <myungjoo.ham@samsung.com>
---
drivers/devfreq/devfreq.c | 6 ++++++
include/linux/devfreq.h | 2 ++
2 files changed, 8 insertions(+)
diff --git a/drivers/devfreq/devfreq.c b/drivers/devfreq/devfreq.c
index 6fecd11dafdd..1103a3ae5586 100644
--- a/drivers/devfreq/devfreq.c
+++ b/drivers/devfreq/devfreq.c
@@ -719,6 +719,8 @@ static void devfreq_dev_release(struct device *dev)
if (devfreq->profile->exit)
devfreq->profile->exit(devfreq->dev.parent);
+ if (devfreq->opp_table)
+ dev_pm_opp_put_opp_table(devfreq->opp_table);
mutex_destroy(&devfreq->lock);
kfree(devfreq);
}
@@ -797,6 +799,10 @@ struct devfreq *devfreq_add_device(struct device *dev,
}
devfreq->suspend_freq = dev_pm_opp_get_suspend_opp_freq(dev);
+ devfreq->opp_table = dev_pm_opp_get_opp_table(dev);
+ if (IS_ERR(devfreq->opp_table))
+ devfreq->opp_table = NULL;
+
atomic_set(&devfreq->suspend_count, 0);
dev_set_name(&devfreq->dev, "%s", dev_name(dev));
diff --git a/include/linux/devfreq.h b/include/linux/devfreq.h
index 57e871a559a9..a4b19d593151 100644
--- a/include/linux/devfreq.h
+++ b/include/linux/devfreq.h
@@ -131,6 +131,7 @@ struct devfreq_stats {
* @profile: device-specific devfreq profile
* @governor: method how to choose frequency based on the usage.
* @governor_name: devfreq governor name for use with this devfreq
+ * @opp_table: Reference to OPP table of dev.parent, if one exists.
* @nb: notifier block used to notify devfreq object that it should
* reevaluate operable frequencies. Devfreq users may use
* devfreq.nb to the corresponding register notifier call chain.
@@ -168,6 +169,7 @@ struct devfreq {
struct devfreq_dev_profile *profile;
const struct devfreq_governor *governor;
char governor_name[DEVFREQ_NAME_LEN];
+ struct opp_table *opp_table;
struct notifier_block nb;
struct delayed_work work;
--
2.12.5
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply related
* [PATCH 05/12] PM / devfreq: Add required OPPs support to passive governor
From: Andrew-sh.Cheng @ 2020-05-20 3:43 UTC (permalink / raw)
To: MyungJoo Ham, Kyungmin Park, Chanwoo Choi, Rob Herring,
Mark Rutland, Matthias Brugger, Rafael J . Wysocki, Viresh Kumar,
Nishanth Menon, Stephen Boyd, Liam Girdwood, Mark Brown
Cc: devicetree, Saravana Kannan, srv_heupstream, linux-pm,
linux-kernel, linux-mediatek, linux-arm-kernel
In-Reply-To: <20200520034307.20435-1-andrew-sh.cheng@mediatek.com>
From: Saravana Kannan <saravanak@google.com>
Look at the required OPPs of the "parent" device to determine the OPP that
is required from the slave device managed by the passive governor. This
allows having mappings between a parent device and a slave device even when
they don't have the same number of OPPs.
Signed-off-by: Saravana Kannan <saravanak@google.com>
Acked-by: MyungJoo Ham <myungjoo.ham@samsung.com>
Acked-by: Chanwoo Choi <cw00.choi@samsung.com>
---
drivers/devfreq/governor_passive.c | 20 +++++++++++++++-----
1 file changed, 15 insertions(+), 5 deletions(-)
diff --git a/drivers/devfreq/governor_passive.c b/drivers/devfreq/governor_passive.c
index be6eeab9c814..2d67d6c12dce 100644
--- a/drivers/devfreq/governor_passive.c
+++ b/drivers/devfreq/governor_passive.c
@@ -19,7 +19,7 @@ static int devfreq_passive_get_target_freq(struct devfreq *devfreq,
= (struct devfreq_passive_data *)devfreq->data;
struct devfreq *parent_devfreq = (struct devfreq *)p_data->parent;
unsigned long child_freq = ULONG_MAX;
- struct dev_pm_opp *opp;
+ struct dev_pm_opp *opp = NULL, *p_opp = NULL;
int i, count, ret = 0;
/*
@@ -56,13 +56,20 @@ static int devfreq_passive_get_target_freq(struct devfreq *devfreq,
* list of parent device. Because in this case, *freq is temporary
* value which is decided by ondemand governor.
*/
- opp = devfreq_recommended_opp(parent_devfreq->dev.parent, freq, 0);
- if (IS_ERR(opp)) {
- ret = PTR_ERR(opp);
+ p_opp = devfreq_recommended_opp(parent_devfreq->dev.parent, freq, 0);
+ if (IS_ERR(p_opp)) {
+ ret = PTR_ERR(p_opp);
goto out;
}
- dev_pm_opp_put(opp);
+ if (devfreq->opp_table && parent_devfreq->opp_table)
+ opp = dev_pm_opp_xlate_required_opp(parent_devfreq->opp_table,
+ devfreq->opp_table, p_opp);
+ if (opp) {
+ *freq = dev_pm_opp_get_freq(opp);
+ dev_pm_opp_put(opp);
+ goto out;
+ }
/*
* Get the OPP table's index of decided freqeuncy by governor
@@ -89,6 +96,9 @@ static int devfreq_passive_get_target_freq(struct devfreq *devfreq,
*freq = child_freq;
out:
+ if (!IS_ERR_OR_NULL(opp))
+ dev_pm_opp_put(p_opp);
+
return ret;
}
--
2.12.5
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply related
* [PATCH 06/12] PM / devfreq: Add cpu based scaling support to passive_governor
From: Andrew-sh.Cheng @ 2020-05-20 3:43 UTC (permalink / raw)
To: MyungJoo Ham, Kyungmin Park, Chanwoo Choi, Rob Herring,
Mark Rutland, Matthias Brugger, Rafael J . Wysocki, Viresh Kumar,
Nishanth Menon, Stephen Boyd, Liam Girdwood, Mark Brown
Cc: devicetree, Andrew-sh . Cheng, srv_heupstream, linux-pm,
linux-kernel, Saravana Kannan, linux-mediatek, Sibi Sankar,
linux-arm-kernel
In-Reply-To: <20200520034307.20435-1-andrew-sh.cheng@mediatek.com>
From: Saravana Kannan <skannan@codeaurora.org>
Many CPU architectures have caches that can scale independent of the
CPUs. Frequency scaling of the caches is necessary to make sure that the
cache is not a performance bottleneck that leads to poor performance and
power. The same idea applies for RAM/DDR.
To achieve this, this patch adds support for cpu based scaling to the
passive governor. This is accomplished by taking the current frequency
of each CPU frequency domain and then adjust the frequency of the cache
(or any devfreq device) based on the frequency of the CPUs. It listens
to CPU frequency transition notifiers to keep itself up to date on the
current CPU frequency.
To decide the frequency of the device, the governor does one of the
following:
* Derives the optimal devfreq device opp from required-opps property of
the parent cpu opp_table.
* Scales the device frequency in proportion to the CPU frequency. So, if
the CPUs are running at their max frequency, the device runs at its
max frequency. If the CPUs are running at their min frequency, the
device runs at its min frequency. It is interpolated for frequencies
in between.
Andrew-sh.Cheng change
dev_pm_opp_xlate_opp to dev_pm_opp_xlate_required_opp devfreq->max_freq
to devfreq->user_min_freq_req.data.freq.qos->min_freq.target_value
for kernel-5.7
Signed-off-by: Saravana Kannan <skannan@codeaurora.org>
[Sibi: Integrated cpu-freqmap governor into passive_governor]
Signed-off-by: Sibi Sankar <sibis@codeaurora.org>
Signed-off-by: Andrew-sh.Cheng <andrew-sh.cheng@mediatek.com>
---
drivers/devfreq/Kconfig | 2 +
drivers/devfreq/governor_passive.c | 278 ++++++++++++++++++++++++++++++++++---
include/linux/devfreq.h | 40 +++++-
3 files changed, 299 insertions(+), 21 deletions(-)
diff --git a/drivers/devfreq/Kconfig b/drivers/devfreq/Kconfig
index 0b1df12e0f21..d9067950af6a 100644
--- a/drivers/devfreq/Kconfig
+++ b/drivers/devfreq/Kconfig
@@ -73,6 +73,8 @@ config DEVFREQ_GOV_PASSIVE
device. This governor does not change the frequency by itself
through sysfs entries. The passive governor recommends that
devfreq device uses the OPP table to get the frequency/voltage.
+ Alternatively the governor can also be chosen to scale based on
+ the online CPUs current frequency.
comment "DEVFREQ Drivers"
diff --git a/drivers/devfreq/governor_passive.c b/drivers/devfreq/governor_passive.c
index 2d67d6c12dce..7dcda02a5bb7 100644
--- a/drivers/devfreq/governor_passive.c
+++ b/drivers/devfreq/governor_passive.c
@@ -8,11 +8,89 @@
*/
#include <linux/module.h>
+#include <linux/cpu.h>
+#include <linux/cpufreq.h>
+#include <linux/cpumask.h>
#include <linux/device.h>
#include <linux/devfreq.h>
+#include <linux/slab.h>
#include "governor.h"
-static int devfreq_passive_get_target_freq(struct devfreq *devfreq,
+static unsigned int xlate_cpufreq_to_devfreq(struct devfreq_passive_data *data,
+ unsigned int cpu)
+{
+ unsigned int cpu_min, cpu_max, dev_min, dev_max, cpu_percent, max_state;
+ struct devfreq_cpu_state *cpu_state = data->cpu_state[cpu];
+ struct devfreq *devfreq = (struct devfreq *)data->this;
+ unsigned long *freq_table = devfreq->profile->freq_table;
+ struct dev_pm_opp *opp = NULL, *cpu_opp = NULL;
+ unsigned long cpu_freq, freq;
+
+ if (!cpu_state || cpu_state->first_cpu != cpu ||
+ !cpu_state->opp_table || !devfreq->opp_table)
+ return 0;
+
+ cpu_freq = cpu_state->freq * 1000;
+ cpu_opp = devfreq_recommended_opp(cpu_state->dev, &cpu_freq, 0);
+ if (IS_ERR(cpu_opp))
+ return 0;
+
+ opp = dev_pm_opp_xlate_required_opp(cpu_state->opp_table,
+ devfreq->opp_table, cpu_opp);
+ dev_pm_opp_put(cpu_opp);
+
+ if (!IS_ERR(opp)) {
+ freq = dev_pm_opp_get_freq(opp);
+ dev_pm_opp_put(opp);
+ } else {
+ /* Use Interpolation if required opps is not available */
+ cpu_min = cpu_state->min_freq;
+ cpu_max = cpu_state->max_freq;
+ cpu_freq = cpu_state->freq;
+
+ if (freq_table) {
+ /* Get minimum frequency according to sorting order */
+ max_state = freq_table[devfreq->profile->max_state - 1];
+ if (freq_table[0] < max_state) {
+ dev_min = freq_table[0];
+ dev_max = max_state;
+ } else {
+ dev_min = max_state;
+ dev_max = freq_table[0];
+ }
+ } else {
+ if (devfreq->user_max_freq_req.data.freq.qos->max_freq.target_value
+ <= devfreq->user_min_freq_req.data.freq.qos->min_freq.target_value)
+ return 0;
+ dev_min =
+ devfreq->user_min_freq_req.data.freq.qos->min_freq.target_value;
+ dev_max =
+ devfreq->user_max_freq_req.data.freq.qos->max_freq.target_value;
+ }
+ cpu_percent = ((cpu_freq - cpu_min) * 100) / cpu_max - cpu_min;
+ freq = dev_min + mult_frac(dev_max - dev_min, cpu_percent, 100);
+ }
+
+ return freq;
+}
+
+static int get_target_freq_with_cpufreq(struct devfreq *devfreq,
+ unsigned long *freq)
+{
+ struct devfreq_passive_data *p_data =
+ (struct devfreq_passive_data *)devfreq->data;
+ unsigned int cpu, target_freq = 0;
+
+ for_each_online_cpu(cpu)
+ target_freq = max(target_freq,
+ xlate_cpufreq_to_devfreq(p_data, cpu));
+
+ *freq = target_freq;
+
+ return 0;
+}
+
+static int get_target_freq_with_devfreq(struct devfreq *devfreq,
unsigned long *freq)
{
struct devfreq_passive_data *p_data
@@ -23,16 +101,6 @@ static int devfreq_passive_get_target_freq(struct devfreq *devfreq,
int i, count, ret = 0;
/*
- * If the devfreq device with passive governor has the specific method
- * to determine the next frequency, should use the get_target_freq()
- * of struct devfreq_passive_data.
- */
- if (p_data->get_target_freq) {
- ret = p_data->get_target_freq(devfreq, freq);
- goto out;
- }
-
- /*
* If the parent and passive devfreq device uses the OPP table,
* get the next frequency by using the OPP table.
*/
@@ -102,6 +170,37 @@ static int devfreq_passive_get_target_freq(struct devfreq *devfreq,
return ret;
}
+static int devfreq_passive_get_target_freq(struct devfreq *devfreq,
+ unsigned long *freq)
+{
+ struct devfreq_passive_data *p_data =
+ (struct devfreq_passive_data *)devfreq->data;
+ int ret;
+
+ /*
+ * If the devfreq device with passive governor has the specific method
+ * to determine the next frequency, should use the get_target_freq()
+ * of struct devfreq_passive_data.
+ */
+ if (p_data->get_target_freq)
+ return p_data->get_target_freq(devfreq, freq);
+
+ switch (p_data->parent_type) {
+ case DEVFREQ_PARENT_DEV:
+ ret = get_target_freq_with_devfreq(devfreq, freq);
+ break;
+ case CPUFREQ_PARENT_DEV:
+ ret = get_target_freq_with_cpufreq(devfreq, freq);
+ break;
+ default:
+ ret = -EINVAL;
+ dev_err(&devfreq->dev, "Invalid parent type\n");
+ break;
+ }
+
+ return ret;
+}
+
static int update_devfreq_passive(struct devfreq *devfreq, unsigned long freq)
{
int ret;
@@ -156,6 +255,140 @@ static int devfreq_passive_notifier_call(struct notifier_block *nb,
return NOTIFY_DONE;
}
+static int cpufreq_passive_notifier_call(struct notifier_block *nb,
+ unsigned long event, void *ptr)
+{
+ struct devfreq_passive_data *data =
+ container_of(nb, struct devfreq_passive_data, nb);
+ struct devfreq *devfreq = (struct devfreq *)data->this;
+ struct devfreq_cpu_state *cpu_state;
+ struct cpufreq_freqs *freq = ptr;
+ unsigned int current_freq;
+ int ret;
+
+ if (event != CPUFREQ_POSTCHANGE || !freq ||
+ !data->cpu_state[freq->policy->cpu])
+ return 0;
+
+ cpu_state = data->cpu_state[freq->policy->cpu];
+ if (cpu_state->freq == freq->new)
+ return 0;
+
+ /* Backup current freq and pre-update cpu state freq*/
+ current_freq = cpu_state->freq;
+ cpu_state->freq = freq->new;
+
+ mutex_lock(&devfreq->lock);
+ ret = update_devfreq(devfreq);
+ mutex_unlock(&devfreq->lock);
+ if (ret) {
+ cpu_state->freq = current_freq;
+ dev_err(&devfreq->dev, "Couldn't update the frequency.\n");
+ return ret;
+ }
+
+ return 0;
+}
+
+static int cpufreq_passive_register(struct devfreq_passive_data **p_data)
+{
+ struct devfreq_passive_data *data = *p_data;
+ struct devfreq *devfreq = (struct devfreq *)data->this;
+ struct device *dev = devfreq->dev.parent;
+ struct opp_table *opp_table = NULL;
+ struct devfreq_cpu_state *state;
+ struct cpufreq_policy *policy;
+ struct device *cpu_dev;
+ unsigned int cpu;
+ int ret;
+
+ get_online_cpus();
+ data->nb.notifier_call = cpufreq_passive_notifier_call;
+ ret = cpufreq_register_notifier(&data->nb,
+ CPUFREQ_TRANSITION_NOTIFIER);
+ if (ret) {
+ dev_err(dev, "Couldn't register cpufreq notifier.\n");
+ data->nb.notifier_call = NULL;
+ goto out;
+ }
+
+ /* Populate devfreq_cpu_state */
+ for_each_online_cpu(cpu) {
+ if (data->cpu_state[cpu])
+ continue;
+
+ policy = cpufreq_cpu_get(cpu);
+ if (policy) {
+ state = kzalloc(sizeof(*state), GFP_KERNEL);
+ if (!state) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ cpu_dev = get_cpu_device(cpu);
+ if (!cpu_dev) {
+ dev_err(dev, "Couldn't get cpu device.\n");
+ ret = -ENODEV;
+ goto out;
+ }
+
+ opp_table = dev_pm_opp_get_opp_table(cpu_dev);
+ if (IS_ERR(devfreq->opp_table)) {
+ ret = PTR_ERR(opp_table);
+ goto out;
+ }
+
+ state->dev = cpu_dev;
+ state->opp_table = opp_table;
+ state->first_cpu = cpumask_first(policy->related_cpus);
+ state->freq = policy->cur;
+ state->min_freq = policy->cpuinfo.min_freq;
+ state->max_freq = policy->cpuinfo.max_freq;
+ data->cpu_state[cpu] = state;
+ cpufreq_cpu_put(policy);
+ } else {
+ ret = -EPROBE_DEFER;
+ goto out;
+ }
+ }
+out:
+ put_online_cpus();
+ if (ret)
+ return ret;
+
+ /* Update devfreq */
+ mutex_lock(&devfreq->lock);
+ ret = update_devfreq(devfreq);
+ mutex_unlock(&devfreq->lock);
+ if (ret)
+ dev_err(dev, "Couldn't update the frequency.\n");
+
+ return ret;
+}
+
+static int cpufreq_passive_unregister(struct devfreq_passive_data **p_data)
+{
+ struct devfreq_passive_data *data = *p_data;
+ struct devfreq_cpu_state *cpu_state;
+ int cpu;
+
+ if (data->nb.notifier_call)
+ cpufreq_unregister_notifier(&data->nb,
+ CPUFREQ_TRANSITION_NOTIFIER);
+
+ for_each_possible_cpu(cpu) {
+ cpu_state = data->cpu_state[cpu];
+ if (cpu_state) {
+ if (cpu_state->opp_table)
+ dev_pm_opp_put_opp_table(cpu_state->opp_table);
+ kfree(cpu_state);
+ cpu_state = NULL;
+ }
+ }
+
+ return 0;
+}
+
static int devfreq_passive_event_handler(struct devfreq *devfreq,
unsigned int event, void *data)
{
@@ -165,7 +398,7 @@ static int devfreq_passive_event_handler(struct devfreq *devfreq,
struct notifier_block *nb = &p_data->nb;
int ret = 0;
- if (!parent)
+ if (p_data->parent_type == DEVFREQ_PARENT_DEV && !parent)
return -EPROBE_DEFER;
switch (event) {
@@ -173,13 +406,24 @@ static int devfreq_passive_event_handler(struct devfreq *devfreq,
if (!p_data->this)
p_data->this = devfreq;
- nb->notifier_call = devfreq_passive_notifier_call;
- ret = devfreq_register_notifier(parent, nb,
- DEVFREQ_TRANSITION_NOTIFIER);
+ if (p_data->parent_type == DEVFREQ_PARENT_DEV) {
+ nb->notifier_call = devfreq_passive_notifier_call;
+ ret = devfreq_register_notifier(parent, nb,
+ DEVFREQ_TRANSITION_NOTIFIER);
+ } else if (p_data->parent_type == CPUFREQ_PARENT_DEV) {
+ ret = cpufreq_passive_register(&p_data);
+ } else {
+ ret = -EINVAL;
+ }
break;
case DEVFREQ_GOV_STOP:
- WARN_ON(devfreq_unregister_notifier(parent, nb,
- DEVFREQ_TRANSITION_NOTIFIER));
+ if (p_data->parent_type == DEVFREQ_PARENT_DEV)
+ WARN_ON(devfreq_unregister_notifier(parent, nb,
+ DEVFREQ_TRANSITION_NOTIFIER));
+ else if (p_data->parent_type == CPUFREQ_PARENT_DEV)
+ cpufreq_passive_unregister(&p_data);
+ else
+ ret = -EINVAL;
break;
default:
break;
diff --git a/include/linux/devfreq.h b/include/linux/devfreq.h
index a4b19d593151..04ce576fd6f1 100644
--- a/include/linux/devfreq.h
+++ b/include/linux/devfreq.h
@@ -278,6 +278,32 @@ struct devfreq_simple_ondemand_data {
#if IS_ENABLED(CONFIG_DEVFREQ_GOV_PASSIVE)
/**
+ * struct devfreq_cpu_state - holds the per-cpu state
+ * @freq: the current frequency of the cpu.
+ * @min_freq: the min frequency of the cpu.
+ * @max_freq: the max frequency of the cpu.
+ * @first_cpu: the cpumask of the first cpu of a policy.
+ * @dev: reference to cpu device.
+ * @opp_table: reference to cpu opp table.
+ *
+ * This structure stores the required cpu_state of a cpu.
+ * This is auto-populated by the governor.
+ */
+struct devfreq_cpu_state {
+ unsigned int freq;
+ unsigned int min_freq;
+ unsigned int max_freq;
+ unsigned int first_cpu;
+ struct device *dev;
+ struct opp_table *opp_table;
+};
+
+enum devfreq_parent_dev_type {
+ DEVFREQ_PARENT_DEV,
+ CPUFREQ_PARENT_DEV,
+};
+
+/**
* struct devfreq_passive_data - ``void *data`` fed to struct devfreq
* and devfreq_add_device
* @parent: the devfreq instance of parent device.
@@ -288,13 +314,15 @@ struct devfreq_simple_ondemand_data {
* using governors except for passive governor.
* If the devfreq device has the specific method to decide
* the next frequency, should use this callback.
- * @this: the devfreq instance of own device.
- * @nb: the notifier block for DEVFREQ_TRANSITION_NOTIFIER list
+ * @parent_type parent type of the device
+ * @this: the devfreq instance of own device.
+ * @nb: the notifier block for DEVFREQ_TRANSITION_NOTIFIER list
+ * @cpu_state: the state min/max/current frequency of all online cpu's
*
* The devfreq_passive_data have to set the devfreq instance of parent
* device with governors except for the passive governor. But, don't need to
- * initialize the 'this' and 'nb' field because the devfreq core will handle
- * them.
+ * initialize the 'this', 'nb' and 'cpu_state' field because the devfreq core
+ * will handle them.
*/
struct devfreq_passive_data {
/* Should set the devfreq instance of parent device */
@@ -303,9 +331,13 @@ struct devfreq_passive_data {
/* Optional callback to decide the next frequency of passvice device */
int (*get_target_freq)(struct devfreq *this, unsigned long *freq);
+ /* Should set the type of parent device */
+ enum devfreq_parent_dev_type parent_type;
+
/* For passive governor's internal use. Don't need to set them */
struct devfreq *this;
struct notifier_block nb;
+ struct devfreq_cpu_state *cpu_state[NR_CPUS];
};
#endif
--
2.12.5
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply related
* [PATCH 08/12] dt-bindings: devfreq: add compatible for mt8183 cci devfreq
From: Andrew-sh.Cheng @ 2020-05-20 3:43 UTC (permalink / raw)
To: MyungJoo Ham, Kyungmin Park, Chanwoo Choi, Rob Herring,
Mark Rutland, Matthias Brugger, Rafael J . Wysocki, Viresh Kumar,
Nishanth Menon, Stephen Boyd, Liam Girdwood, Mark Brown
Cc: devicetree, Andrew-sh.Cheng, srv_heupstream, linux-pm,
linux-kernel, linux-mediatek, linux-arm-kernel
In-Reply-To: <20200520034307.20435-1-andrew-sh.cheng@mediatek.com>
This adds dt-binding documentation of cci devfreq
for Mediatek MT8183 SoC platform.
Signed-off-by: Andrew-sh.Cheng <andrew-sh.cheng@mediatek.com>
---
.../devicetree/bindings/devfreq/mt8183-cci.yaml | 51 ++++++++++++++++++++++
1 file changed, 51 insertions(+)
create mode 100644 Documentation/devicetree/bindings/devfreq/mt8183-cci.yaml
diff --git a/Documentation/devicetree/bindings/devfreq/mt8183-cci.yaml b/Documentation/devicetree/bindings/devfreq/mt8183-cci.yaml
new file mode 100644
index 000000000000..a7341fd94097
--- /dev/null
+++ b/Documentation/devicetree/bindings/devfreq/mt8183-cci.yaml
@@ -0,0 +1,51 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/devfreq/mt8183-cci.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: CCI_DEVFREQ driver for MT8183.
+
+maintainers:
+ - Andrew-sh.Cheng <andrew-sh.cheng@mediatek.com>
+
+description: |
+ This module is used to create CCI DEVFREQ.
+ The performance will depend on both CCI frequency and CPU frequency.
+ For MT8183, CCI co-buck with Little core.
+ Contain CCI opp table for voltage and frequency scaling.
+
+properties:
+ compatible:
+ const: "mediatek,mt8183-cci"
+
+ clocks:
+ maxItems: 1
+
+ clock-names:
+ const: "cci"
+
+ operating-points-v2: true
+ opp-table: true
+
+ proc-supply:
+ description:
+ Phandle of the regulator that provides the supply voltage.
+
+required:
+ - compatible
+ - clocks
+ - clock-names
+ - proc-supply
+
+examples:
+ - |
+ #include <dt-bindings/clock/mt8183-clk.h>
+ cci: cci {
+ compatible = "mediatek,mt8183-cci";
+ clocks = <&apmixedsys CLK_APMIXED_CCIPLL>;
+ clock-names = "cci";
+ operating-points-v2 = <&cci_opp>;
+ proc-supply = <&mt6358_vproc12_reg>;
+ };
+
--
2.12.5
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply related
* [PATCH 10/12] opp: Modify opp API, dev_pm_opp_get_freq(), find freq in opp, even it is disabled
From: Andrew-sh.Cheng @ 2020-05-20 3:43 UTC (permalink / raw)
To: MyungJoo Ham, Kyungmin Park, Chanwoo Choi, Rob Herring,
Mark Rutland, Matthias Brugger, Rafael J . Wysocki, Viresh Kumar,
Nishanth Menon, Stephen Boyd, Liam Girdwood, Mark Brown
Cc: devicetree, Andrew-sh.Cheng, srv_heupstream, linux-pm,
linux-kernel, linux-mediatek, linux-arm-kernel
In-Reply-To: <20200520034307.20435-1-andrew-sh.cheng@mediatek.com>
Modify dev_pm_opp_get_freq() to return freqeuncy
even this opp item is not available.
So that we can get the information of disable opp items.
Signed-off-by: Andrew-sh.Cheng <andrew-sh.cheng@mediatek.com>
---
drivers/opp/core.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/opp/core.c b/drivers/opp/core.c
index 284b01223831..04d9171604c5 100644
--- a/drivers/opp/core.c
+++ b/drivers/opp/core.c
@@ -118,7 +118,7 @@ EXPORT_SYMBOL_GPL(dev_pm_opp_get_voltage);
*/
unsigned long dev_pm_opp_get_freq(struct dev_pm_opp *opp)
{
- if (IS_ERR_OR_NULL(opp) || !opp->available) {
+ if (IS_ERR_OR_NULL(opp)) {
pr_err("%s: Invalid parameters\n", __func__);
return 0;
}
--
2.12.5
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply related
* [PATCH 07/12] cpufreq: mediatek: Enable clock and regulator
From: Andrew-sh.Cheng @ 2020-05-20 3:43 UTC (permalink / raw)
To: MyungJoo Ham, Kyungmin Park, Chanwoo Choi, Rob Herring,
Mark Rutland, Matthias Brugger, Rafael J . Wysocki, Viresh Kumar,
Nishanth Menon, Stephen Boyd, Liam Girdwood, Mark Brown
Cc: devicetree, Andrew-sh.Cheng, srv_heupstream, linux-pm,
linux-kernel, linux-mediatek, linux-arm-kernel
In-Reply-To: <20200520034307.20435-1-andrew-sh.cheng@mediatek.com>
Need to enable regulator,
so that the max/min requested value will be recorded
even it is not applied right away.
Intermediate clock is not always enabled by ccf in different projects,
so cpufreq should always enable used clock by itself.
Signed-off-by: Andrew-sh.Cheng <andrew-sh.cheng@mediatek.com>
---
drivers/cpufreq/mediatek-cpufreq.c | 33 +++++++++++++++++++++++++++++----
1 file changed, 29 insertions(+), 4 deletions(-)
diff --git a/drivers/cpufreq/mediatek-cpufreq.c b/drivers/cpufreq/mediatek-cpufreq.c
index 0c98dd08273d..4b479c110cc9 100644
--- a/drivers/cpufreq/mediatek-cpufreq.c
+++ b/drivers/cpufreq/mediatek-cpufreq.c
@@ -350,6 +350,11 @@ static int mtk_cpu_dvfs_info_init(struct mtk_cpu_dvfs_info *info, int cpu)
ret = PTR_ERR(proc_reg);
goto out_free_resources;
}
+ ret = regulator_enable(proc_reg);
+ if (ret) {
+ pr_warn("enable vproc for cpu%d fail\n", cpu);
+ goto out_free_resources;
+ }
/* Both presence and absence of sram regulator are valid cases. */
sram_reg = regulator_get_exclusive(cpu_dev, "sram");
@@ -368,13 +373,21 @@ static int mtk_cpu_dvfs_info_init(struct mtk_cpu_dvfs_info *info, int cpu)
goto out_free_resources;
}
+ ret = clk_prepare_enable(cpu_clk);
+ if (ret)
+ goto out_free_opp_table;
+
+ ret = clk_prepare_enable(inter_clk);
+ if (ret)
+ goto out_disable_mux_clock;
+
/* Search a safe voltage for intermediate frequency. */
rate = clk_get_rate(inter_clk);
opp = dev_pm_opp_find_freq_ceil(cpu_dev, &rate);
if (IS_ERR(opp)) {
pr_err("failed to get intermediate opp for cpu%d\n", cpu);
ret = PTR_ERR(opp);
- goto out_free_opp_table;
+ goto out_disable_inter_clock;
}
info->intermediate_voltage = dev_pm_opp_get_voltage(opp);
dev_pm_opp_put(opp);
@@ -393,6 +406,12 @@ static int mtk_cpu_dvfs_info_init(struct mtk_cpu_dvfs_info *info, int cpu)
return 0;
+out_disable_inter_clock:
+ clk_disable_unprepare(inter_clk);
+
+out_disable_mux_clock:
+ clk_disable_unprepare(cpu_clk);
+
out_free_opp_table:
dev_pm_opp_of_cpumask_remove_table(&info->cpus);
@@ -411,14 +430,20 @@ static int mtk_cpu_dvfs_info_init(struct mtk_cpu_dvfs_info *info, int cpu)
static void mtk_cpu_dvfs_info_release(struct mtk_cpu_dvfs_info *info)
{
- if (!IS_ERR(info->proc_reg))
+ if (!IS_ERR(info->proc_reg)) {
+ regulator_disable(info->proc_reg);
regulator_put(info->proc_reg);
+ }
if (!IS_ERR(info->sram_reg))
regulator_put(info->sram_reg);
- if (!IS_ERR(info->cpu_clk))
+ if (!IS_ERR(info->cpu_clk)) {
+ clk_disable_unprepare(info->cpu_clk);
clk_put(info->cpu_clk);
- if (!IS_ERR(info->inter_clk))
+ }
+ if (!IS_ERR(info->inter_clk)) {
+ clk_disable_unprepare(info->inter_clk);
clk_put(info->inter_clk);
+ }
dev_pm_opp_of_cpumask_remove_table(&info->cpus);
}
--
2.12.5
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply related
* [PATCH v11] arm64: dts: qcom: sc7180: Add WCN3990 WLAN module device node
From: Rakesh Pillai @ 2020-05-20 3:56 UTC (permalink / raw)
To: devicetree; +Cc: linux-arm-msm, Rakesh Pillai, linux-kernel, linux-arm-kernel
Add device node for the ath10k SNOC platform driver probe
and add resources required for WCN3990 on sc7180 soc.
Signed-off-by: Rakesh Pillai <pillair@codeaurora.org>
---
Changes from v10:
- Corrected the position of wifi node, as per address
- Removed the wlan_fw_mem from reserved memory, since
its already added as reserved memory in board DT file.
---
arch/arm64/boot/dts/qcom/sc7180-idp.dts | 7 +++++++
arch/arm64/boot/dts/qcom/sc7180.dtsi | 22 ++++++++++++++++++++++
2 files changed, 29 insertions(+)
diff --git a/arch/arm64/boot/dts/qcom/sc7180-idp.dts b/arch/arm64/boot/dts/qcom/sc7180-idp.dts
index 4e9149d..38b102e 100644
--- a/arch/arm64/boot/dts/qcom/sc7180-idp.dts
+++ b/arch/arm64/boot/dts/qcom/sc7180-idp.dts
@@ -389,6 +389,13 @@
};
};
+&wifi {
+ status = "okay";
+ wifi-firmware {
+ iommus = <&apps_smmu 0xc2 0x1>;
+ };
+};
+
/* PINCTRL - additions to nodes defined in sc7180.dtsi */
&qspi_clk {
diff --git a/arch/arm64/boot/dts/qcom/sc7180.dtsi b/arch/arm64/boot/dts/qcom/sc7180.dtsi
index 6b12c60..da79f8f 100644
--- a/arch/arm64/boot/dts/qcom/sc7180.dtsi
+++ b/arch/arm64/boot/dts/qcom/sc7180.dtsi
@@ -2811,6 +2811,28 @@
#freq-domain-cells = <1>;
};
+
+ wifi: wifi@18800000 {
+ compatible = "qcom,wcn3990-wifi";
+ reg = <0 0x18800000 0 0x800000>;
+ reg-names = "membase";
+ iommus = <&apps_smmu 0xc0 0x1>;
+ interrupts =
+ <GIC_SPI 414 IRQ_TYPE_LEVEL_HIGH /* CE0 */ >,
+ <GIC_SPI 415 IRQ_TYPE_LEVEL_HIGH /* CE1 */ >,
+ <GIC_SPI 416 IRQ_TYPE_LEVEL_HIGH /* CE2 */ >,
+ <GIC_SPI 417 IRQ_TYPE_LEVEL_HIGH /* CE3 */ >,
+ <GIC_SPI 418 IRQ_TYPE_LEVEL_HIGH /* CE4 */ >,
+ <GIC_SPI 419 IRQ_TYPE_LEVEL_HIGH /* CE5 */ >,
+ <GIC_SPI 420 IRQ_TYPE_LEVEL_HIGH /* CE6 */ >,
+ <GIC_SPI 421 IRQ_TYPE_LEVEL_HIGH /* CE7 */ >,
+ <GIC_SPI 422 IRQ_TYPE_LEVEL_HIGH /* CE8 */ >,
+ <GIC_SPI 423 IRQ_TYPE_LEVEL_HIGH /* CE9 */ >,
+ <GIC_SPI 424 IRQ_TYPE_LEVEL_HIGH /* CE10 */>,
+ <GIC_SPI 425 IRQ_TYPE_LEVEL_HIGH /* CE11 */>;
+ memory-region = <&wlan_mem>;
+ status = "disabled";
+ };
};
thermal-zones {
--
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 related
* Re: [PATCH 00/12] Add cpufreq and cci devfreq for mt8183, and SVS support
From: Chanwoo Choi @ 2020-05-20 4:10 UTC (permalink / raw)
To: Andrew-sh.Cheng, MyungJoo Ham, Kyungmin Park, Rob Herring,
Mark Rutland, Matthias Brugger, Rafael J . Wysocki, Viresh Kumar,
Nishanth Menon, Stephen Boyd, Liam Girdwood, Mark Brown
Cc: devicetree, srv_heupstream, linux-pm, linux-kernel,
linux-mediatek, linux-arm-kernel
In-Reply-To: <20200520034307.20435-1-andrew-sh.cheng@mediatek.com>
Hi Andrew,
Could you explain the base commit of these patches?
When I tried to apply them to v5.7-rc1 for testing,
the merge conflict occurs.
Thanks,
Chanwoo Choi
On 5/20/20 12:42 PM, Andrew-sh.Cheng wrote:
> MT8183 supports CPU DVFS and CCI DVFS, and LITTLE cpus and CCI are in the same voltage domain.
> So, this series is to add drivers to handle the voltage coupling between CPU and CCI DVFS.
>
> For SVS support, need OPP_EVENT_ADJUST_VOLTAGE and corresponding reaction.
>
> Change since v5:
> - Changing dt-binding format to yaml.
> - Extending current devfreq passive_governor instead of create a new one.
> - Resend depending patches of Sravana Kannan base on kernel-5.7
>
>
> Andrew-sh.Cheng (6):
> cpufreq: mediatek: add clock and regulator enable for intermediate
> clock
> dt-bindings: devfreq: add compatible for mt8183 cci devfreq
> devfreq: add mediatek cci devfreq
> opp: Modify opp API, dev_pm_opp_get_freq(), find freq in opp, even it
> is disabled
> cpufreq: mediatek: add opp notification for SVS support
> devfreq: mediatek: cci devfreq register opp notification for SVS
> support
>
> Saravana Kannan (6):
> OPP: Allow required-opps even if the device doesn't have power-domains
> OPP: Add function to look up required OPP's for a given OPP
> OPP: Improve required-opps linking
> PM / devfreq: Cache OPP table reference in devfreq
> PM / devfreq: Add required OPPs support to passive governor
> PM / devfreq: Add cpu based scaling support to passive_governor
>
> .../devicetree/bindings/devfreq/mt8183-cci.yaml | 51 ++++
> drivers/cpufreq/mediatek-cpufreq.c | 122 ++++++++-
> drivers/devfreq/Kconfig | 12 +
> drivers/devfreq/Makefile | 1 +
> drivers/devfreq/devfreq.c | 6 +
> drivers/devfreq/governor_passive.c | 298 +++++++++++++++++++--
> drivers/devfreq/mt8183-cci-devfreq.c | 233 ++++++++++++++++
> drivers/opp/core.c | 85 +++++-
> drivers/opp/of.c | 108 ++++----
> drivers/opp/opp.h | 5 +
> include/linux/devfreq.h | 42 ++-
> include/linux/pm_opp.h | 11 +
> 12 files changed, 874 insertions(+), 100 deletions(-)
> create mode 100644 Documentation/devicetree/bindings/devfreq/mt8183-cci.yaml
> create mode 100644 drivers/devfreq/mt8183-cci-devfreq.c
>
_______________________________________________
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