* Re: [PATCH v2 1/4] dt-bindings: phy: Add support for QUSB2 phy
From: Vivek Gautam @ 2016-11-29 5:20 UTC (permalink / raw)
To: Rob Herring
Cc: kishon, Mark Rutland, devicetree@vger.kernel.org,
linux-kernel@vger.kernel.org, Srinivas Kandagatla, Stephen Boyd,
linux-arm-msm
In-Reply-To: <20161128141944.4sfptmymh5kcpcwm@rob-hp-laptop>
Hi Rob,
On Mon, Nov 28, 2016 at 7:49 PM, Rob Herring <robh@kernel.org> wrote:
Thanks for reviewing the patch.
> On Tue, Nov 22, 2016 at 05:32:40PM +0530, Vivek Gautam wrote:
>> Qualcomm chipsets have QUSB2 phy controller that provides
>> HighSpeed functionality for DWC3 controller.
>> Adding dt binding information for the same.
>>
>> Signed-off-by: Vivek Gautam <vivek.gautam@codeaurora.org>
>> ---
>>
>> Changes since v1:
>> - New patch, forked out of the original driver patch:
>> "phy: qcom-qusb2: New driver for QUSB2 PHY on Qcom chips"
>> - Updated dt bindings to remove 'hstx-trim-bit-offset' and
>> 'hstx-trim-bit-len' bindings.
>>
>> .../devicetree/bindings/phy/qcom-qusb2-phy.txt | 55 ++++++++++++++++++++++
>> 1 file changed, 55 insertions(+)
>> create mode 100644 Documentation/devicetree/bindings/phy/qcom-qusb2-phy.txt
>>
>> diff --git a/Documentation/devicetree/bindings/phy/qcom-qusb2-phy.txt b/Documentation/devicetree/bindings/phy/qcom-qusb2-phy.txt
>> new file mode 100644
>> index 0000000..38c8b30
>> --- /dev/null
>> +++ b/Documentation/devicetree/bindings/phy/qcom-qusb2-phy.txt
>> @@ -0,0 +1,55 @@
>> +Qualcomm QUSB2 phy controller
>> +=============================
>> +
>> +QUSB2 controller supports LS/FS/HS usb connectivity on Qualcomm chipsets.
>> +
>> +Required properties:
>> + - compatible: compatible list, contains "qcom,msm8996-qusb2-phy".
>> + - reg: offset and length of the PHY register set.
>> + - #phy-cells: must be 0.
>> +
>> + - clocks: a list of phandles and clock-specifier pairs,
>> + one for each entry in clock-names.
>> + - clock-names: must be "cfg_ahb" for phy config clock,
>> + "ref_clk" for 19.2 MHz ref clk,
>> + "ref_clk_src" reference clock source.
>> + "iface" for phy interface clock (Optional).
>> +
>> + - vdd-phy-supply: Phandle to a regulator supply to PHY core block.
>> + - vdda-pll-supply: Phandle to 1.8V regulator supply to PHY refclk pll block.
>> + - vdda-phy-dpdm: Phandle to 3.1V regulator supply to Dp/Dm port signals.
>
> Needs '-supply'
sure, will add.
>
>> +
>> + - resets: a list of phandles and reset controller specifier pairs,
>> + one for each entry in reset-names.
>> + - reset-names: must be "phy" for reset of phy block.
>> +
>> +Optional properties:
>> + - nvmem-cells: a list of phandles to nvmem cells that contain fused
>> + tuning parameters for qusb2 phy, one for each entry
>> + in nvmem-cell-names.
>> + - nvmem-cell-names: must be "tune2_hstx_trim_efuse" for cell containing
>> + HS Tx trim value.
>> +
>> + - qcom,tcsr-syscon: Phandle to TCSR syscon register region.
>> +
>> +Example:
>> + hsphy: qusb2phy@7411000 {
>
> usb-phy@...
Or may be just 'phy' for the node name, and then label could be 'usb_hs_phy'?
[...]
Thanks
Vivek
--
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum,
a Linux Foundation Collaborative Project
^ permalink raw reply
* Re: [PATCH v2 1/4] dt-bindings: phy: Add support for QUSB2 phy
From: Vivek Gautam @ 2016-11-29 5:22 UTC (permalink / raw)
To: Stephen Boyd
Cc: kishon, robh+dt, Mark Rutland, devicetree@vger.kernel.org,
linux-kernel@vger.kernel.org, Srinivas Kandagatla, linux-arm-msm
In-Reply-To: <20161128224953.GL6095@codeaurora.org>
Hi Stephen,
On Tue, Nov 29, 2016 at 4:19 AM, Stephen Boyd <sboyd@codeaurora.org> wrote:
Thanks for reviewing the patch-series.
> On 11/22, Vivek Gautam wrote:
>> diff --git a/Documentation/devicetree/bindings/phy/qcom-qusb2-phy.txt b/Documentation/devicetree/bindings/phy/qcom-qusb2-phy.txt
>> new file mode 100644
>> index 0000000..38c8b30
>> --- /dev/null
>> +++ b/Documentation/devicetree/bindings/phy/qcom-qusb2-phy.txt
>> @@ -0,0 +1,55 @@
>> +Optional properties:
>> + - nvmem-cells: a list of phandles to nvmem cells that contain fused
>> + tuning parameters for qusb2 phy, one for each entry
>> + in nvmem-cell-names.
>> + - nvmem-cell-names: must be "tune2_hstx_trim_efuse" for cell containing
>
> Do we really need efuse in the name? Seems redundant given this
> is already an nvmem.
Correct, we don't need 'efuse' in the name. Thanks for pointing out.
Best Regards
Vivek
--
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum,
a Linux Foundation Collaborative Project
^ permalink raw reply
* Re: [PATCH v2 3/4] dt-bindings: phy: Add support for QMP phy
From: Vivek Gautam @ 2016-11-29 5:25 UTC (permalink / raw)
To: Stephen Boyd
Cc: kishon, robh+dt, Mark Rutland, devicetree@vger.kernel.org,
linux-kernel@vger.kernel.org, Srinivas Kandagatla, linux-arm-msm
In-Reply-To: <20161128225543.GM6095@codeaurora.org>
Hi,
On Tue, Nov 29, 2016 at 4:25 AM, Stephen Boyd <sboyd@codeaurora.org> wrote:
> On 11/22, Vivek Gautam wrote:
>> diff --git a/Documentation/devicetree/bindings/phy/qcom-qmp-phy.txt b/Documentation/devicetree/bindings/phy/qcom-qmp-phy.txt
>> new file mode 100644
>> index 0000000..ffb173b
>> --- /dev/null
>> +++ b/Documentation/devicetree/bindings/phy/qcom-qmp-phy.txt
>> @@ -0,0 +1,74 @@
>> +Qualcomm QMP PHY
>> +----------------
>> +
>> +QMP phy controller supports physical layer functionality for a number of
>> +controllers on Qualcomm chipsets, such as, PCIe, UFS, and USB.
>> +
>> +Required properties:
>> + - compatible: compatible list, contains:
>> + "qcom,msm8996-qmp-pcie-phy" for 14nm PCIe phy on msm8996,
>> + "qcom,msm8996-qmp-usb3-phy" for 14nm USB3 phy on msm8996.
>> + - reg: list of offset and length pair of the PHY register sets.
>> + at index 0: offset and length of register set for PHY common
>> + serdes block.
>> + from index 1 - N: offset and length of register set for each lane,
>> + for N number of phy lanes (ports).
>> + - lane-offsets: array of offsets to tx, rx and pcs blocks for phy lanes.
>> + - #phy-cells: must be 1
>> + - Cell after phy phandle should be the port (lane) number.
>> + - clocks: a list of phandles and clock-specifier pairs,
>> + one for each entry in clock-names.
>> + - clock-names: must be "cfg_ahb" for phy config clock,
>> + "aux" for phy aux clock,
>> + "ref_clk" for 19.2 MHz ref clk,
>> + "ref_clk_src" for reference clock source,
>
> We typically leave "clk" out of clk names because it's redundant.
Right, will drop 'clk' from these names.
>
>> + "pipe<port-number>" for pipe clock specific to
>> + each port/lane (Optional).
>
> The pipe clocks are orphaned right now. We should add an output
> clock from the phy to go into the controller and back into the
> phy if I recall correctly. The phy should be a clock provider
> itself so it can output the pipe clock source into GCC and back
> into the phy and controller.
>
>> + - resets: a list of phandles and reset controller specifier pairs,
>> + one for each entry in reset-names.
>> + - reset-names: must be "phy" for reset of phy block,
>> + "common" for phy common block reset,
>> + "cfg" for phy's ahb cfg block reset (Optional).
>> + "port<port-number>" for reset specific to
>> + each port/lane (Optional).
>> + - vdda-phy-supply: Phandle to a regulator supply to PHY core block.
>> + - vdda-pll-supply: Phandle to 1.8V regulator supply to PHY refclk pll block.
>> +
>> +Optional properties:
>> + - vddp-ref-clk-supply: Phandle to a regulator supply to any specific refclk
>> + pll block.
>> +
>> +Example:
>> + pcie_phy: pciephy@34000 {
>
> pcie-phy or just phy as the node name?
How about just 'phy'? The label pcie_phy anyways explains the use.
Thanks
Vivek
--
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum,
a Linux Foundation Collaborative Project
^ permalink raw reply
* Re: [PATCH v2 0/3] increase TSCADC clock to 24MHz and fix ti,charge-delay to represent in nS
From: Mugunthan V N @ 2016-11-29 5:41 UTC (permalink / raw)
To: Dmitry Torokhov
Cc: Lee Jones, linux-input-u79uwXL29TY76Z2rM5mHXA, Jonathan Cameron,
Rob Herring, Mark Rutland, Sekhar Nori, Vignesh R,
devicetree-u79uwXL29TY76Z2rM5mHXA,
linux-omap-u79uwXL29TY76Z2rM5mHXA,
linux-kernel-u79uwXL29TY76Z2rM5mHXA
In-Reply-To: <20161125095918.GZ10134-Re9dqnLqz4GzQB+pC5nmwQ@public.gmane.org>
On Friday 25 November 2016 03:29 PM, Lee Jones wrote:
> On Fri, 25 Nov 2016, Mugunthan V N wrote:
>
>> Hi Dmitry Torokhov,
>>
>> On Thursday 10 November 2016 10:05 PM, Mugunthan V N wrote:
>>> This patch series enables ADC to be clocked at 24MHz as the
>>> TI AM335x ADC driver has already adopted to use DMA to transfer
>>> ADC samples. Now ADC can generated upto 800K Samples per second
>>> with the patch [1] on AM335x BBB and AM437x GP EVM.
>>>
>>> when ADC ref clock is set at 24MHz, I am seeing some issue with
>>> touch screen pointer as the pointer jumps to random locations
>>> with free draw application. The issue is due to increase in ADC
>>> clock and charge delay for the touchscreen ADC line duration
>>> reduced.
>>>
>>> So the notation of ti,charge-delay in terms of ADC clock is
>>> wrong, it has to be represented in time and driver has to convert
>>> the charge delay time to ADC clocks based on what ADC clock
>>> frequency is set.
>>>
>>> Measured the performance with the iio_generic_buffer with the
>>> patch [2] applied
>>>
>>> Verified the touch screen on AM335x GP EVM and AM335x BBB LCD7
>>> cape with [3] dts for display and touch screen to work.
>>>
>>
>> Since there are acks from DT and MFD maintainers, can you pull the patch
>> series if you do not have any more comments.
>
> Cant do anything without *all* Acks.
>
Hi Dmitry Torokhov,
Can you provide your inputs on the patch series.
Regards
Mugunthan V N
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply
* Re: Question regarding clocks in the DW-HDMI DT bindings
From: Laurent Pinchart @ 2016-11-29 6:04 UTC (permalink / raw)
To: Michael Turquette
Cc: Andy Yan, Vladimir Zapolskiy, Fabio Estevam, DRI mailing list,
Linux-DT, Stephen Boyd, nickey.yang-TNX95d0MmH7DzftRWevZcw
In-Reply-To: <CAEG3pNDtMY+Pf1_w6vQEswaMVZ=jOC69R749jSFwB2NiU8r58Q-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
Hi Mike,
On Monday 28 Nov 2016 13:56:11 Michael Turquette wrote:
> On Fri, Nov 25, 2016 at 7:22 AM, Laurent Pinchart wrote:
> > On Friday 25 Nov 2016 10:56:53 Andy Yan wrote:
> >> On 2016年11月25日 07:26, Laurent Pinchart wrote:
> >>> On Friday 25 Nov 2016 00:16:00 Vladimir Zapolskiy wrote:
> >>>> On 11/25/2016 12:07 AM, Fabio Estevam wrote:
> >>>>> On Thu, Nov 24, 2016 at 7:16 PM, Laurent Pinchart wrote:
> >>>>>> Hi Andy,
> >>>>>>
> >>>>>> As the author of the DW-HDMI DT bindings this question is addressed
> >>>>>> to you, but information from anyone is more than welcome.
> >>>>>>
> >>>>>> The DT bindings specify two clocks named "iahb" and "isfr" but don't
> >>>>>> describe them. While I assume that the "isfr" clock corresponds to
> >>>>>> the "isfrclk" input signal of the DW HDMI, there is no "iahb" clock
> >>>>>> described in the IP core datasheet.
> >>>>>
> >>>>> i.MX6Q has a DW-HDMI IP block.
> >>>>>
> >>>>> The names in the devicetree binding matches the ones listed at the
> >>>>> i.MX6Q Reference Manual - Table 33-1. HDMI Clocks
> >>>>
> >>>> correct, for your convenience the table is copied below:
> >>>>
> >>>> Clock name | Clock Root | Description
> >>>> -----------+--------------------+-------------------------------------
> >>>> iahbclk | ahb_clk_root | Bus clock
> >>>> icecclk | ckil_sync_clk_root | CEC low-frequency clock (32kHZ)
> >>>> ihclk | ahb_clk_root | Module clock
> >>>> isfrclk | video_27m_clk_root | Internal SFR clock (video clock
> >>>> 27MHz)
> >>>>
> >>>> Here AHB stands for ARM Advanced High-performance Bus.
> >>>
> >>> That's what I suspected. I believe the "iahb" name is wrong, as the DW
> >>> HDMI TX IP core clearly documents the bus clock as being called
> >>> "iapbclk". We could rename that in the DT bindings (with compatibility
> >>> code in the driver to keep supporting the old name) but it might not be
> >>> worth it. The bindings should however document that the "iahb" clock is
> >>> the IP core's "iapbclk" bus clock.
> >>
> >> I got the clock name from I.MX6Q TRM, I also checked the name again
> >> with Rockchip IC design team now, hope to get some new information soon.
> >
> > Thank you. While at it, could you ask them which version of the DW HDMI IP
> > used in the SoC ?
> >
> >>> Another question I have about the bus clock (CC'ing the devicetree
> >>> mailing list as well as the clock maintainers) is whether it should be
> >>> made optional. The clock is obviously mandatory from a hardware point
> >>> of view (given that APB is a synchronous bus and thus requires a
> >>> clock), but in some SoCs (specifically for the Renesas SoCs) that clock
> >>> is always on and can't be controlled. We already omit bus clocks in DT
> >>> for most IP cores when the clock can never be controlled (and we also
> >>> omit a bunch of other clocks that we don't even know exist), so it
> >>> could make sense to make the clock optional. Otherwise there would be
> >>> runtime overhead trying to handle a clock that can't be controlled.
> >>
> >> If this is the case on Renesas SOCs, we can consider make the clock as
> >> optional. Or move all the clock operations to platform specific
> >> code(dw_hdmi-rockchip.c/dw_hdmi-imx.c)?
> >
> > I'd prefer keeping the code generic, otherwise we'd end up with platform-
> > specific code that would perform the same operations on most platforms.
> > I'll submit a patch soon to make the clock optional, we can discuss it
> > then.
>
> Yes, let's keep the code generic. Absence of a "standard' clock is OK
> and we should accept the small overhead incurred in providing a
> solution that works for everyone. This prevents hardware-specific
> hacks in the driver.
>
> Related: we really should model bus clocks whenever possible. I've
> seen other attempts to merge functional/logic and bus clocks into a
> single entity (e.g. a single struct clk_hw/clk_core that turns both
> clocks on and off) and this defeats some fine-grained power management
> scenarios that the hardware designers had in mind when creating
> separate controls for the clocks.
Sure, but that wasn't really the question :-) When the bus clock is separately
controllable then I agree it should be modelled separately in DT. In my case
the bus clock is always on, and I'm thus wondering whether it would be better
to make it optional in DT to reduce the runtime overhead incurred by trying to
control something that can't be controlled.
> >>>> By the way while we're discussing DW HDMI bindings specific to iMX,
> >>>> I would recommend to remove utterly hackish and iMX only "gpr"
> >>>> property from the example in bindings/display/bridge/dw_hdmi.txt
--
Regards,
Laurent Pinchart
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply
* [PATCH v3 1/2] dt-bindings: drm/bridge: adv7511: Add regulator bindings
From: Archit Taneja @ 2016-11-29 6:07 UTC (permalink / raw)
To: laurent.pinchart-ryLnwIuWjnjg/C1BVhZhaw
Cc: linux-arm-msm-u79uwXL29TY76Z2rM5mHXA, robh-DgEjT+Ai2ygdnm+yROfE0A,
dri-devel-PD4FTy7X32lNgt0PjOBp9y5qC8QIuHrW, Archit Taneja,
devicetree-u79uwXL29TY76Z2rM5mHXA
In-Reply-To: <1480399662-8858-1-git-send-email-architt-sgV2jX0FEOL9JmXXK+q4OQ@public.gmane.org>
Add the regulator supply properties needed by ADV7511 and ADV7533.
The regulators are specified as optional properties since there can
be boards which have a fixed supply directly routed to the pins, and
these may not be modelled as regulator supplies.
Cc: devicetree-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
Acked-by: Rob Herring <robh-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org>
Signed-off-by: Archit Taneja <architt-sgV2jX0FEOL9JmXXK+q4OQ@public.gmane.org>
---
v3:
- Revert back to having a common avdd-supply property for the 1.8V
supplies
Documentation/devicetree/bindings/display/bridge/adi,adv7511.txt | 9 +++++++++
1 file changed, 9 insertions(+)
diff --git a/Documentation/devicetree/bindings/display/bridge/adi,adv7511.txt b/Documentation/devicetree/bindings/display/bridge/adi,adv7511.txt
index 6532a59..13d53bc 100644
--- a/Documentation/devicetree/bindings/display/bridge/adi,adv7511.txt
+++ b/Documentation/devicetree/bindings/display/bridge/adi,adv7511.txt
@@ -56,6 +56,15 @@ Optional properties:
- adi,disable-timing-generator: Only for ADV7533. Disables the internal timing
generator. The chip will rely on the sync signals in the DSI data lanes,
rather than generate its own timings for HDMI output.
+- avdd-supply: A common 1.8V supply that powers up the AVDD, DVDD and PVDD
+ pins. On ADV7511, it also feeds to the BGVDD pin. On ADV7533, it also powers
+ up the A2VDD pin.
+- v3p3-supply: A 3.3V supply that powers up the pin called DVDD_3V on
+ ADV7511 and V3P3 on ADV7533.
+
+ADV7533 specific supplies:
+- v1p2-supply: A supply that powers up the V1P2 pin on the chip. It can be
+ either 1.2V or 1.8V.
Required nodes:
--
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
hosted by The Linux Foundation
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply related
* [PATCH] arm64: dts: exynos: Add support for s6e3ha2 panel device for TM2
From: Hoegeun Kwon @ 2016-11-29 6:16 UTC (permalink / raw)
To: kgene, krzk, devicetree
Cc: linux-samsung-soc, hoegeun.kwon, Hyungwon Hwang, Andrzej Hajda,
Chanwoo Choi
From: Hyungwon Hwang <human.hwang@samsung.com>
This patch adds the Panel Device Tree node for s6e3ha2 display
controller to Exynos5433 SoC dts.
Signed-off-by: Hyungwon Hwang <human.hwang@samsung.com>
Signed-off-by: Andrzej Hajda <a.hajda@samsung.com>
Signed-off-by: Chanwoo Choi <cw00.choi@samsung.com>
Signed-off-by: Hoegeun Kwon <hoegeun.kwon@samsung.com>
---
arch/arm64/boot/dts/exynos/exynos5433-tm2.dts | 35 +++++++++++++++++++++++++++
1 file changed, 35 insertions(+)
diff --git a/arch/arm64/boot/dts/exynos/exynos5433-tm2.dts b/arch/arm64/boot/dts/exynos/exynos5433-tm2.dts
index db879f4..d27f27d 100644
--- a/arch/arm64/boot/dts/exynos/exynos5433-tm2.dts
+++ b/arch/arm64/boot/dts/exynos/exynos5433-tm2.dts
@@ -252,11 +252,46 @@
reg = <1>;
dsi_out: endpoint {
+ remote-endpoint = <&dsi_in>;
samsung,burst-clock-frequency = <512000000>;
samsung,esc-clock-frequency = <16000000>;
};
};
};
+
+ panel@0 {
+ compatible = "samsung,s6e3ha2";
+ reg = <0>;
+ vdd3-supply = <&ldo27_reg>;
+ vci-supply = <&ldo28_reg>;
+ reset-gpios = <&gpg0 0 0>;
+ panel-en-gpios = <&gpf1 5 0>;
+ te-gpios = <&gpf1 3 1>;
+ power-on-delay= <5>;
+ init-delay = <120>;
+ panel-width-mm = <71>;
+ panel-height-mm = <125>;
+
+ display-timings {
+ timing-0 {
+ clock-frequency = <14874444>;
+ hactive = <1440>;
+ vactive = <2560>;
+ hfront-porch = <1>;
+ hback-porch = <1>;
+ hsync-len = <1>;
+ vfront-porch = <1>;
+ vback-porch = <15>;
+ vsync-len = <1>;
+ };
+ };
+
+ port {
+ dsi_in: endpoint {
+ remote-endpoint = <&dsi_out>;
+ };
+ };
+ };
};
&hsi2c_0 {
--
1.9.1
^ permalink raw reply related
* Re: Question regarding clocks in the DW-HDMI DT bindings
From: Michael Turquette @ 2016-11-29 6:27 UTC (permalink / raw)
To: Laurent Pinchart
Cc: Andy Yan, Vladimir Zapolskiy, Fabio Estevam, DRI mailing list,
Linux-DT, nickey.yang-TNX95d0MmH7DzftRWevZcw, Stephen Boyd
In-Reply-To: <1938338.cMuGjElf2l@avalon>
Hi Laurent,
[fixing Stephen's email address]
On Mon, Nov 28, 2016 at 10:04 PM, Laurent Pinchart
<laurent.pinchart-ryLnwIuWjnjg/C1BVhZhaw@public.gmane.org> wrote:
> Hi Mike,
>
> On Monday 28 Nov 2016 13:56:11 Michael Turquette wrote:
>> On Fri, Nov 25, 2016 at 7:22 AM, Laurent Pinchart wrote:
>> > On Friday 25 Nov 2016 10:56:53 Andy Yan wrote:
>> >> On 2016年11月25日 07:26, Laurent Pinchart wrote:
>> >>> On Friday 25 Nov 2016 00:16:00 Vladimir Zapolskiy wrote:
>> >>>> On 11/25/2016 12:07 AM, Fabio Estevam wrote:
>> >>>>> On Thu, Nov 24, 2016 at 7:16 PM, Laurent Pinchart wrote:
>> >>>>>> Hi Andy,
>> >>>>>>
>> >>>>>> As the author of the DW-HDMI DT bindings this question is addressed
>> >>>>>> to you, but information from anyone is more than welcome.
>> >>>>>>
>> >>>>>> The DT bindings specify two clocks named "iahb" and "isfr" but don't
>> >>>>>> describe them. While I assume that the "isfr" clock corresponds to
>> >>>>>> the "isfrclk" input signal of the DW HDMI, there is no "iahb" clock
>> >>>>>> described in the IP core datasheet.
>> >>>>>
>> >>>>> i.MX6Q has a DW-HDMI IP block.
>> >>>>>
>> >>>>> The names in the devicetree binding matches the ones listed at the
>> >>>>> i.MX6Q Reference Manual - Table 33-1. HDMI Clocks
>> >>>>
>> >>>> correct, for your convenience the table is copied below:
>> >>>>
>> >>>> Clock name | Clock Root | Description
>> >>>> -----------+--------------------+-------------------------------------
>> >>>> iahbclk | ahb_clk_root | Bus clock
>> >>>> icecclk | ckil_sync_clk_root | CEC low-frequency clock (32kHZ)
>> >>>> ihclk | ahb_clk_root | Module clock
>> >>>> isfrclk | video_27m_clk_root | Internal SFR clock (video clock
>> >>>> 27MHz)
>> >>>>
>> >>>> Here AHB stands for ARM Advanced High-performance Bus.
>> >>>
>> >>> That's what I suspected. I believe the "iahb" name is wrong, as the DW
>> >>> HDMI TX IP core clearly documents the bus clock as being called
>> >>> "iapbclk". We could rename that in the DT bindings (with compatibility
>> >>> code in the driver to keep supporting the old name) but it might not be
>> >>> worth it. The bindings should however document that the "iahb" clock is
>> >>> the IP core's "iapbclk" bus clock.
>> >>
>> >> I got the clock name from I.MX6Q TRM, I also checked the name again
>> >> with Rockchip IC design team now, hope to get some new information soon.
>> >
>> > Thank you. While at it, could you ask them which version of the DW HDMI IP
>> > used in the SoC ?
>> >
>> >>> Another question I have about the bus clock (CC'ing the devicetree
>> >>> mailing list as well as the clock maintainers) is whether it should be
>> >>> made optional. The clock is obviously mandatory from a hardware point
>> >>> of view (given that APB is a synchronous bus and thus requires a
>> >>> clock), but in some SoCs (specifically for the Renesas SoCs) that clock
>> >>> is always on and can't be controlled. We already omit bus clocks in DT
>> >>> for most IP cores when the clock can never be controlled (and we also
>> >>> omit a bunch of other clocks that we don't even know exist), so it
>> >>> could make sense to make the clock optional. Otherwise there would be
>> >>> runtime overhead trying to handle a clock that can't be controlled.
>> >>
>> >> If this is the case on Renesas SOCs, we can consider make the clock as
>> >> optional. Or move all the clock operations to platform specific
>> >> code(dw_hdmi-rockchip.c/dw_hdmi-imx.c)?
>> >
>> > I'd prefer keeping the code generic, otherwise we'd end up with platform-
>> > specific code that would perform the same operations on most platforms.
>> > I'll submit a patch soon to make the clock optional, we can discuss it
>> > then.
>>
>> Yes, let's keep the code generic. Absence of a "standard' clock is OK
>> and we should accept the small overhead incurred in providing a
>> solution that works for everyone. This prevents hardware-specific
>> hacks in the driver.
>>
>> Related: we really should model bus clocks whenever possible. I've
>> seen other attempts to merge functional/logic and bus clocks into a
>> single entity (e.g. a single struct clk_hw/clk_core that turns both
>> clocks on and off) and this defeats some fine-grained power management
>> scenarios that the hardware designers had in mind when creating
>> separate controls for the clocks.
>
> Sure, but that wasn't really the question :-) When the bus clock is separately
> controllable then I agree it should be modelled separately in DT. In my case
> the bus clock is always on, and I'm thus wondering whether it would be better
> to make it optional in DT to reduce the runtime overhead incurred by trying to
> control something that can't be controlled.
I thought I answered this, but maybe not directly enough :-)
We should make the clock mandatory in DT if the physical line must be
there. This is regardless of whether a given chip/IP variant has
control over that clock; so long as the physical clock line always
exists then it is not really "optional".
In the case where there is an absence of the physical clock line, then
making it optional in DT makes sense.
As an aside, we did discuss the fact that the vast majority of clocks
are not modeled in DT, and I'm not saying that we transcribe the RTL
into DT. I'm just saying that if there is a debate over whether or not
to make a clock optional in DT, when it is always physically there,
then don't make it optional. Whether or not the control is exposed on
a particular chip is less important.
Anyways, this is more DT ridiculousness and I won't block either
method getting merged. I'm just picking my favorite color to paint the
bikeshed.
Regards,
Mike
>
>> >>>> By the way while we're discussing DW HDMI bindings specific to iMX,
>> >>>> I would recommend to remove utterly hackish and iMX only "gpr"
>> >>>> property from the example in bindings/display/bridge/dw_hdmi.txt
>
> --
> Regards,
>
> Laurent Pinchart
>
--
Michael Turquette
CEO
BayLibre - At the Heart of Embedded Linux
http://baylibre.com/
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply
* Re: [PATCH v3 1/2] dt-bindings: drm/bridge: adv7511: Add regulator bindings
From: Laurent Pinchart @ 2016-11-29 6:33 UTC (permalink / raw)
To: Archit Taneja
Cc: linux-arm-msm-u79uwXL29TY76Z2rM5mHXA, robh-DgEjT+Ai2ygdnm+yROfE0A,
dri-devel-PD4FTy7X32lNgt0PjOBp9y5qC8QIuHrW,
devicetree-u79uwXL29TY76Z2rM5mHXA
In-Reply-To: <1480399662-8858-2-git-send-email-architt-sgV2jX0FEOL9JmXXK+q4OQ@public.gmane.org>
Hi Archit,
Thank you for the patch.
On Tuesday 29 Nov 2016 11:37:41 Archit Taneja wrote:
> Add the regulator supply properties needed by ADV7511 and ADV7533.
>
> The regulators are specified as optional properties since there can
> be boards which have a fixed supply directly routed to the pins, and
> these may not be modelled as regulator supplies.
That's why we have support for dummy supplies in the kernel, isn't it ? Isn't
it better to make the supplies mandatory in the bindings (and obviously
handling them as optional in the driver for backward-compatibility) ?
Apart from that,
Acked-by: Laurent Pinchart <laurent.pinchart-ryLnwIuWjnjg/C1BVhZhaw@public.gmane.org>
> Cc: devicetree-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
> Acked-by: Rob Herring <robh-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org>
> Signed-off-by: Archit Taneja <architt-sgV2jX0FEOL9JmXXK+q4OQ@public.gmane.org>
> ---
> v3:
> - Revert back to having a common avdd-supply property for the 1.8V
> supplies
>
> Documentation/devicetree/bindings/display/bridge/adi,adv7511.txt | 9 ++++++
> 1 file changed, 9 insertions(+)
>
> diff --git
> a/Documentation/devicetree/bindings/display/bridge/adi,adv7511.txt
> b/Documentation/devicetree/bindings/display/bridge/adi,adv7511.txt index
> 6532a59..13d53bc 100644
> --- a/Documentation/devicetree/bindings/display/bridge/adi,adv7511.txt
> +++ b/Documentation/devicetree/bindings/display/bridge/adi,adv7511.txt
> @@ -56,6 +56,15 @@ Optional properties:
> - adi,disable-timing-generator: Only for ADV7533. Disables the internal
> timing generator. The chip will rely on the sync signals in the DSI data
> lanes, rather than generate its own timings for HDMI output.
> +- avdd-supply: A common 1.8V supply that powers up the AVDD, DVDD and PVDD
> + pins. On ADV7511, it also feeds to the BGVDD pin. On ADV7533, it also
> powers
> + up the A2VDD pin.
> +- v3p3-supply: A 3.3V supply that powers up the pin called DVDD_3V on
> + ADV7511 and V3P3 on ADV7533.
> +
> +ADV7533 specific supplies:
> +- v1p2-supply: A supply that powers up the V1P2 pin on the chip. It can be
> + either 1.2V or 1.8V.
>
> Required nodes:
--
Regards,
Laurent Pinchart
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply
* [PATCH V5 00/10] PM / OPP: Multiple regulator support
From: Viresh Kumar @ 2016-11-29 6:36 UTC (permalink / raw)
To: Rafael Wysocki, nm-l0cyMroinI0, sboyd-sgV2jX0FEOL9JmXXK+q4OQ
Cc: linaro-kernel-cunTk1MwBs8s++Sfvej+rw,
linux-pm-u79uwXL29TY76Z2rM5mHXA,
linux-kernel-u79uwXL29TY76Z2rM5mHXA, Vincent Guittot,
robh-DgEjT+Ai2ygdnm+yROfE0A, d-gerlach-l0cyMroinI0,
broonie-DgEjT+Ai2ygdnm+yROfE0A, devicetree-u79uwXL29TY76Z2rM5mHXA,
Viresh Kumar
Hi,
Some platforms (like TI) have complex DVFS configuration for CPU
devices, where multiple regulators are required to be configured to
change DVFS state of the device. This was explained well by Nishanth
earlier [1].
One of the major complaints around multiple regulators case was that the
DT isn't responsible in any way to represent the order in which multiple
supplies need to be programmed, before or after a frequency change. It
was considered in this patch and such information is left for the
platform specific OPP driver now, which can register its own
opp_set_rate() callback with the OPP core and the OPP core will then
call it during DVFS.
The patches are tested on Exynos5250 (Dual A15). I have hacked around DT
and code to pass values for multiple regulators and verified that they
are all properly read by the kernel (using debugfs interface).
Dave Gerlach has already tested [2] it on the real TI platforms and it
works well for him.
This is rebased over: linux-next branch in the PM tree.
V4->V5:
- Stephen boyd had some minor review comments and gave his Reviewed-by
tag for the rest. Only 2 patches don't have his RBY tag.
- Individual patches contain the version history from V4 to V5.
V3->V4:
- Separate out cpu-supply fix in the binding in a separate patch (Mark).
- Add more documentation to the binding to explain that the relation to
the supplies and the order of programming them is left for the
platform specific bindings and that every platform using multiple
regulators for their devices needs to provide a separate binding
document explaining their implementation (Mark).
- @Rob and Stephen: I have kept your Acks for the bindings as the
bindings only got a bit reworded (improved) since the time you guys
Acked them. Please let me know if you want more improvement in the
bindings now.
- V4 for 10/10 was sent earlier, which added a missing
rcu_read_unlock(). Nothing else changed in it.
- Added some missing Kernel documentation comments
V2->V3:
- The last patch is new
- Removed a debug leftover pr_info() message
- Renamed few names as s/set_rate/set_opp
- Removed a TODO comment (as it is done now with this series)
- created struct for min_uV and max_uV
- kerneldoc comments for structures in pm_opp.h
- s/const char */const char * const
- use kasprintf()
- Some more minor reformatting
- More Ack/RBY tags added
V1->V2:
- Ack from Rob for 1st patch
- Moved the supplies structure to pm_opp.h (Dave)
- Fixed an compilation warning.
--
viresh
[1] https://marc.info/?l=linux-pm&m=145684495832764&w=2
[2] https://marc.info/?l=linux-kernel&m=147924789305276&w=2
Viresh Kumar (10):
PM / OPP: Fix incorrect cpu-supply property in binding
PM / OPP: Reword binding supporting multiple regulators per device
PM / OPP: Don't use OPP structure outside of rcu protected section
PM / OPP: Manage supply's voltage/current in a separate structure
PM / OPP: Pass struct dev_pm_opp_supply to _set_opp_voltage()
PM / OPP: Add infrastructure to manage multiple regulators
PM / OPP: Separate out _generic_set_opp()
PM / OPP: Allow platform specific custom set_opp() callbacks
PM / OPP: Don't WARN on multiple calls to dev_pm_opp_set_regulators()
PM / OPP: Don't assume platform doesn't have regulators
Documentation/devicetree/bindings/opp/opp.txt | 27 +-
drivers/base/power/opp/core.c | 536 ++++++++++++++++++++------
drivers/base/power/opp/debugfs.c | 52 ++-
drivers/base/power/opp/of.c | 105 +++--
drivers/base/power/opp/opp.h | 22 +-
drivers/cpufreq/cpufreq-dt.c | 9 +-
include/linux/pm_opp.h | 69 +++-
7 files changed, 634 insertions(+), 186 deletions(-)
--
2.7.1.410.g6faf27b
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply
* [PATCH V5 01/10] PM / OPP: Fix incorrect cpu-supply property in binding
From: Viresh Kumar @ 2016-11-29 6:36 UTC (permalink / raw)
To: Rafael Wysocki, nm, sboyd, Viresh Kumar
Cc: linaro-kernel, linux-pm, linux-kernel, Vincent Guittot, robh,
d-gerlach, broonie, devicetree, Viresh Kumar
In-Reply-To: <cover.1480401041.git.viresh.kumar@linaro.org>
The regulator bindings allow the "<name>-supply" property to define a
single parent supply and not a list of parents.
Fix the wrong example code present in OPP bindings.
While at it also change the compatible string as Rob pointed out earlier
that none of A7 implementation have multiple supplies for the CPU core.
Signed-off-by: Viresh Kumar <viresh.kumar@linaro.org>
Acked-by: Rob Herring <robh@kernel.org>
Reviewed-by: Stephen Boyd <sboyd@codeaurora.org>
---
Documentation/devicetree/bindings/opp/opp.txt | 6 ++++--
1 file changed, 4 insertions(+), 2 deletions(-)
diff --git a/Documentation/devicetree/bindings/opp/opp.txt b/Documentation/devicetree/bindings/opp/opp.txt
index ee91cbdd95ee..f0239f68d186 100644
--- a/Documentation/devicetree/bindings/opp/opp.txt
+++ b/Documentation/devicetree/bindings/opp/opp.txt
@@ -386,10 +386,12 @@ Example 4: Handling multiple regulators
/ {
cpus {
cpu@0 {
- compatible = "arm,cortex-a7";
+ compatible = "vendor,cpu-type";
...
- cpu-supply = <&cpu_supply0>, <&cpu_supply1>, <&cpu_supply2>;
+ vcc0-supply = <&cpu_supply0>;
+ vcc1-supply = <&cpu_supply1>;
+ vcc2-supply = <&cpu_supply2>;
operating-points-v2 = <&cpu0_opp_table>;
};
};
--
2.7.1.410.g6faf27b
^ permalink raw reply related
* [PATCH V5 02/10] PM / OPP: Reword binding supporting multiple regulators per device
From: Viresh Kumar @ 2016-11-29 6:36 UTC (permalink / raw)
To: Rafael Wysocki, nm, sboyd, Viresh Kumar
Cc: linaro-kernel, linux-pm, linux-kernel, Vincent Guittot, robh,
d-gerlach, broonie, devicetree, Viresh Kumar
In-Reply-To: <cover.1480401041.git.viresh.kumar@linaro.org>
On certain platforms (like TI), DVFS for a single device (CPU) requires
configuring multiple power supplies.
The OPP bindings already contains binding and example to explain this
case, but it isn't sufficient.
- There is no way for the code parsing these bindings to know which
voltage values belong to which power supply.
- It is not possible to know the order in which the supplies need to be
configured while switching OPPs.
This patch clarifies on those details by mentioning that such
information is left for the implementation specific bindings to explain.
They may want to hardcode such details or implement their own properties
to get such information. All implementations using multiple regulators
for their devices must provide a binding document explaining their
implementation.
Signed-off-by: Viresh Kumar <viresh.kumar@linaro.org>
Acked-by: Rob Herring <robh@kernel.org>
Reviewed-by: Stephen Boyd <sboyd@codeaurora.org>
---
Documentation/devicetree/bindings/opp/opp.txt | 21 +++++++++++++++------
1 file changed, 15 insertions(+), 6 deletions(-)
diff --git a/Documentation/devicetree/bindings/opp/opp.txt b/Documentation/devicetree/bindings/opp/opp.txt
index f0239f68d186..9f5ca4457b5f 100644
--- a/Documentation/devicetree/bindings/opp/opp.txt
+++ b/Documentation/devicetree/bindings/opp/opp.txt
@@ -86,8 +86,14 @@ properties.
Single entry is for target voltage and three entries are for <target min max>
voltages.
- Entries for multiple regulators must be present in the same order as
- regulators are specified in device's DT node.
+ Entries for multiple regulators shall be provided in the same field separated
+ by angular brackets <>. The OPP binding doesn't provide any provisions to
+ relate the values to their power supplies or the order in which the supplies
+ need to be configured and that is left for the implementation specific
+ binding.
+
+ Entries for all regulators shall be of the same size, i.e. either all use a
+ single value or triplets.
- opp-microvolt-<name>: Named opp-microvolt property. This is exactly similar to
the above opp-microvolt property, but allows multiple voltage ranges to be
@@ -104,10 +110,13 @@ properties.
Should only be set if opp-microvolt is set for the OPP.
- Entries for multiple regulators must be present in the same order as
- regulators are specified in device's DT node. If this property isn't required
- for few regulators, then this should be marked as zero for them. If it isn't
- required for any regulator, then this property need not be present.
+ Entries for multiple regulators shall be provided in the same field separated
+ by angular brackets <>. If current values aren't required for a regulator,
+ then it shall be filled with 0. If current values aren't required for any of
+ the regulators, then this field is not required. The OPP binding doesn't
+ provide any provisions to relate the values to their power supplies or the
+ order in which the supplies need to be configured and that is left for the
+ implementation specific binding.
- opp-microamp-<name>: Named opp-microamp property. Similar to
opp-microvolt-<name> property, but for microamp instead.
--
2.7.1.410.g6faf27b
^ permalink raw reply related
* [PATCH V5 03/10] PM / OPP: Don't use OPP structure outside of rcu protected section
From: Viresh Kumar @ 2016-11-29 6:36 UTC (permalink / raw)
To: Rafael Wysocki, nm-l0cyMroinI0, sboyd-sgV2jX0FEOL9JmXXK+q4OQ,
Viresh Kumar
Cc: linaro-kernel-cunTk1MwBs8s++Sfvej+rw,
linux-pm-u79uwXL29TY76Z2rM5mHXA,
linux-kernel-u79uwXL29TY76Z2rM5mHXA, Vincent Guittot,
robh-DgEjT+Ai2ygdnm+yROfE0A, d-gerlach-l0cyMroinI0,
broonie-DgEjT+Ai2ygdnm+yROfE0A, devicetree-u79uwXL29TY76Z2rM5mHXA,
Viresh Kumar, # v4 . 6+
In-Reply-To: <cover.1480401041.git.viresh.kumar-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org>
The OPP structure must not be used out of the rcu protected section.
Cache the values to be used in separate variables instead.
Cc: # v4.6+ <stable-u79uwXL29TY76Z2rM5mHXA@public.gmane.org>
Signed-off-by: Viresh Kumar <viresh.kumar-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org>
Reviewed-by: Stephen Boyd <sboyd-sgV2jX0FEOL9JmXXK+q4OQ@public.gmane.org>
Tested-by: Dave Gerlach <d-gerlach-l0cyMroinI0@public.gmane.org>
---
drivers/base/power/opp/core.c | 16 +++++++++++++---
1 file changed, 13 insertions(+), 3 deletions(-)
diff --git a/drivers/base/power/opp/core.c b/drivers/base/power/opp/core.c
index 4c7c6da7a989..056527a3fb4e 100644
--- a/drivers/base/power/opp/core.c
+++ b/drivers/base/power/opp/core.c
@@ -584,6 +584,7 @@ int dev_pm_opp_set_rate(struct device *dev, unsigned long target_freq)
struct clk *clk;
unsigned long freq, old_freq;
unsigned long u_volt, u_volt_min, u_volt_max;
+ unsigned long old_u_volt, old_u_volt_min, old_u_volt_max;
int ret;
if (unlikely(!target_freq)) {
@@ -633,6 +634,14 @@ int dev_pm_opp_set_rate(struct device *dev, unsigned long target_freq)
return ret;
}
+ if (IS_ERR(old_opp)) {
+ old_u_volt = 0;
+ } else {
+ old_u_volt = old_opp->u_volt;
+ old_u_volt_min = old_opp->u_volt_min;
+ old_u_volt_max = old_opp->u_volt_max;
+ }
+
u_volt = opp->u_volt;
u_volt_min = opp->u_volt_min;
u_volt_max = opp->u_volt_max;
@@ -677,9 +686,10 @@ int dev_pm_opp_set_rate(struct device *dev, unsigned long target_freq)
__func__, old_freq);
restore_voltage:
/* This shouldn't harm even if the voltages weren't updated earlier */
- if (!IS_ERR(old_opp))
- _set_opp_voltage(dev, reg, old_opp->u_volt,
- old_opp->u_volt_min, old_opp->u_volt_max);
+ if (old_u_volt) {
+ _set_opp_voltage(dev, reg, old_u_volt, old_u_volt_min,
+ old_u_volt_max);
+ }
return ret;
}
--
2.7.1.410.g6faf27b
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply related
* [PATCH V5 04/10] PM / OPP: Manage supply's voltage/current in a separate structure
From: Viresh Kumar @ 2016-11-29 6:36 UTC (permalink / raw)
To: Rafael Wysocki, nm, sboyd, Viresh Kumar
Cc: linaro-kernel, linux-pm, linux-kernel, Vincent Guittot, robh,
d-gerlach, broonie, devicetree, Viresh Kumar
In-Reply-To: <cover.1480401041.git.viresh.kumar@linaro.org>
This is a preparatory step for multiple regulator per device support.
Move the voltage/current variables to a new structure.
Signed-off-by: Viresh Kumar <viresh.kumar@linaro.org>
Tested-by: Dave Gerlach <d-gerlach@ti.com>
Reviewed-by: Stephen Boyd <sboyd@codeaurora.org>
---
drivers/base/power/opp/core.c | 44 +++++++++++++++++++++-------------------
drivers/base/power/opp/debugfs.c | 8 ++++----
drivers/base/power/opp/of.c | 18 ++++++++--------
drivers/base/power/opp/opp.h | 11 +++-------
include/linux/pm_opp.h | 16 +++++++++++++++
5 files changed, 55 insertions(+), 42 deletions(-)
diff --git a/drivers/base/power/opp/core.c b/drivers/base/power/opp/core.c
index 056527a3fb4e..8d6006151c9a 100644
--- a/drivers/base/power/opp/core.c
+++ b/drivers/base/power/opp/core.c
@@ -112,7 +112,7 @@ unsigned long dev_pm_opp_get_voltage(struct dev_pm_opp *opp)
if (IS_ERR_OR_NULL(tmp_opp))
pr_err("%s: Invalid parameters\n", __func__);
else
- v = tmp_opp->u_volt;
+ v = tmp_opp->supply.u_volt;
return v;
}
@@ -246,10 +246,10 @@ unsigned long dev_pm_opp_get_max_volt_latency(struct device *dev)
if (!opp->available)
continue;
- if (opp->u_volt_min < min_uV)
- min_uV = opp->u_volt_min;
- if (opp->u_volt_max > max_uV)
- max_uV = opp->u_volt_max;
+ if (opp->supply.u_volt_min < min_uV)
+ min_uV = opp->supply.u_volt_min;
+ if (opp->supply.u_volt_max > max_uV)
+ max_uV = opp->supply.u_volt_max;
}
rcu_read_unlock();
@@ -637,14 +637,14 @@ int dev_pm_opp_set_rate(struct device *dev, unsigned long target_freq)
if (IS_ERR(old_opp)) {
old_u_volt = 0;
} else {
- old_u_volt = old_opp->u_volt;
- old_u_volt_min = old_opp->u_volt_min;
- old_u_volt_max = old_opp->u_volt_max;
+ old_u_volt = old_opp->supply.u_volt;
+ old_u_volt_min = old_opp->supply.u_volt_min;
+ old_u_volt_max = old_opp->supply.u_volt_max;
}
- u_volt = opp->u_volt;
- u_volt_min = opp->u_volt_min;
- u_volt_max = opp->u_volt_max;
+ u_volt = opp->supply.u_volt;
+ u_volt_min = opp->supply.u_volt_min;
+ u_volt_max = opp->supply.u_volt_max;
reg = opp_table->regulator;
@@ -957,10 +957,11 @@ static bool _opp_supported_by_regulators(struct dev_pm_opp *opp,
struct regulator *reg = opp_table->regulator;
if (!IS_ERR(reg) &&
- !regulator_is_supported_voltage(reg, opp->u_volt_min,
- opp->u_volt_max)) {
+ !regulator_is_supported_voltage(reg, opp->supply.u_volt_min,
+ opp->supply.u_volt_max)) {
pr_warn("%s: OPP minuV: %lu maxuV: %lu, not supported by regulator\n",
- __func__, opp->u_volt_min, opp->u_volt_max);
+ __func__, opp->supply.u_volt_min,
+ opp->supply.u_volt_max);
return false;
}
@@ -993,11 +994,12 @@ int _opp_add(struct device *dev, struct dev_pm_opp *new_opp,
/* Duplicate OPPs */
dev_warn(dev, "%s: duplicate OPPs detected. Existing: freq: %lu, volt: %lu, enabled: %d. New: freq: %lu, volt: %lu, enabled: %d\n",
- __func__, opp->rate, opp->u_volt, opp->available,
- new_opp->rate, new_opp->u_volt, new_opp->available);
+ __func__, opp->rate, opp->supply.u_volt,
+ opp->available, new_opp->rate, new_opp->supply.u_volt,
+ new_opp->available);
- return opp->available && new_opp->u_volt == opp->u_volt ?
- 0 : -EEXIST;
+ return opp->available &&
+ new_opp->supply.u_volt == opp->supply.u_volt ? 0 : -EEXIST;
}
new_opp->opp_table = opp_table;
@@ -1064,9 +1066,9 @@ int _opp_add_v1(struct device *dev, unsigned long freq, long u_volt,
/* populate the opp table */
new_opp->rate = freq;
tol = u_volt * opp_table->voltage_tolerance_v1 / 100;
- new_opp->u_volt = u_volt;
- new_opp->u_volt_min = u_volt - tol;
- new_opp->u_volt_max = u_volt + tol;
+ new_opp->supply.u_volt = u_volt;
+ new_opp->supply.u_volt_min = u_volt - tol;
+ new_opp->supply.u_volt_max = u_volt + tol;
new_opp->available = true;
new_opp->dynamic = dynamic;
diff --git a/drivers/base/power/opp/debugfs.c b/drivers/base/power/opp/debugfs.c
index ef1ae6b52042..c897676ca35f 100644
--- a/drivers/base/power/opp/debugfs.c
+++ b/drivers/base/power/opp/debugfs.c
@@ -63,16 +63,16 @@ int opp_debug_create_one(struct dev_pm_opp *opp, struct opp_table *opp_table)
if (!debugfs_create_ulong("rate_hz", S_IRUGO, d, &opp->rate))
return -ENOMEM;
- if (!debugfs_create_ulong("u_volt_target", S_IRUGO, d, &opp->u_volt))
+ if (!debugfs_create_ulong("u_volt_target", S_IRUGO, d, &opp->supply.u_volt))
return -ENOMEM;
- if (!debugfs_create_ulong("u_volt_min", S_IRUGO, d, &opp->u_volt_min))
+ if (!debugfs_create_ulong("u_volt_min", S_IRUGO, d, &opp->supply.u_volt_min))
return -ENOMEM;
- if (!debugfs_create_ulong("u_volt_max", S_IRUGO, d, &opp->u_volt_max))
+ if (!debugfs_create_ulong("u_volt_max", S_IRUGO, d, &opp->supply.u_volt_max))
return -ENOMEM;
- if (!debugfs_create_ulong("u_amp", S_IRUGO, d, &opp->u_amp))
+ if (!debugfs_create_ulong("u_amp", S_IRUGO, d, &opp->supply.u_amp))
return -ENOMEM;
if (!debugfs_create_ulong("clock_latency_ns", S_IRUGO, d,
diff --git a/drivers/base/power/opp/of.c b/drivers/base/power/opp/of.c
index 5b3755e49731..bdf409d42126 100644
--- a/drivers/base/power/opp/of.c
+++ b/drivers/base/power/opp/of.c
@@ -148,14 +148,14 @@ static int opp_parse_supplies(struct dev_pm_opp *opp, struct device *dev,
return -EINVAL;
}
- opp->u_volt = microvolt[0];
+ opp->supply.u_volt = microvolt[0];
if (count == 1) {
- opp->u_volt_min = opp->u_volt;
- opp->u_volt_max = opp->u_volt;
+ opp->supply.u_volt_min = opp->supply.u_volt;
+ opp->supply.u_volt_max = opp->supply.u_volt;
} else {
- opp->u_volt_min = microvolt[1];
- opp->u_volt_max = microvolt[2];
+ opp->supply.u_volt_min = microvolt[1];
+ opp->supply.u_volt_max = microvolt[2];
}
/* Search for "opp-microamp-<name>" */
@@ -173,7 +173,7 @@ static int opp_parse_supplies(struct dev_pm_opp *opp, struct device *dev,
}
if (prop && !of_property_read_u32(opp->np, name, &val))
- opp->u_amp = val;
+ opp->supply.u_amp = val;
return 0;
}
@@ -303,9 +303,9 @@ static int _opp_add_static_v2(struct device *dev, struct device_node *np)
mutex_unlock(&opp_table_lock);
pr_debug("%s: turbo:%d rate:%lu uv:%lu uvmin:%lu uvmax:%lu latency:%lu\n",
- __func__, new_opp->turbo, new_opp->rate, new_opp->u_volt,
- new_opp->u_volt_min, new_opp->u_volt_max,
- new_opp->clock_latency_ns);
+ __func__, new_opp->turbo, new_opp->rate,
+ new_opp->supply.u_volt, new_opp->supply.u_volt_min,
+ new_opp->supply.u_volt_max, new_opp->clock_latency_ns);
/*
* Notify the changes in the availability of the operable
diff --git a/drivers/base/power/opp/opp.h b/drivers/base/power/opp/opp.h
index 96cd30ac6c1d..8a02516542c2 100644
--- a/drivers/base/power/opp/opp.h
+++ b/drivers/base/power/opp/opp.h
@@ -61,10 +61,7 @@ extern struct list_head opp_tables;
* @turbo: true if turbo (boost) OPP
* @suspend: true if suspend OPP
* @rate: Frequency in hertz
- * @u_volt: Target voltage in microvolts corresponding to this OPP
- * @u_volt_min: Minimum voltage in microvolts corresponding to this OPP
- * @u_volt_max: Maximum voltage in microvolts corresponding to this OPP
- * @u_amp: Maximum current drawn by the device in microamperes
+ * @supply: Power supply voltage/current values
* @clock_latency_ns: Latency (in nanoseconds) of switching to this OPP's
* frequency from any other OPP's frequency.
* @opp_table: points back to the opp_table struct this opp belongs to
@@ -83,10 +80,8 @@ struct dev_pm_opp {
bool suspend;
unsigned long rate;
- unsigned long u_volt;
- unsigned long u_volt_min;
- unsigned long u_volt_max;
- unsigned long u_amp;
+ struct dev_pm_opp_supply supply;
+
unsigned long clock_latency_ns;
struct opp_table *opp_table;
diff --git a/include/linux/pm_opp.h b/include/linux/pm_opp.h
index bca26157f5b6..f69126e2bb59 100644
--- a/include/linux/pm_opp.h
+++ b/include/linux/pm_opp.h
@@ -24,6 +24,22 @@ enum dev_pm_opp_event {
OPP_EVENT_ADD, OPP_EVENT_REMOVE, OPP_EVENT_ENABLE, OPP_EVENT_DISABLE,
};
+/**
+ * struct dev_pm_opp_supply - Power supply voltage/current values
+ * @u_volt: Target voltage in microvolts corresponding to this OPP
+ * @u_volt_min: Minimum voltage in microvolts corresponding to this OPP
+ * @u_volt_max: Maximum voltage in microvolts corresponding to this OPP
+ * @u_amp: Maximum current drawn by the device in microamperes
+ *
+ * This structure stores the voltage/current values for a single power supply.
+ */
+struct dev_pm_opp_supply {
+ unsigned long u_volt;
+ unsigned long u_volt_min;
+ unsigned long u_volt_max;
+ unsigned long u_amp;
+};
+
#if defined(CONFIG_PM_OPP)
unsigned long dev_pm_opp_get_voltage(struct dev_pm_opp *opp);
--
2.7.1.410.g6faf27b
^ permalink raw reply related
* [PATCH V5 05/10] PM / OPP: Pass struct dev_pm_opp_supply to _set_opp_voltage()
From: Viresh Kumar @ 2016-11-29 6:36 UTC (permalink / raw)
To: Rafael Wysocki, nm, sboyd, Viresh Kumar
Cc: linaro-kernel, linux-pm, linux-kernel, Vincent Guittot, robh,
d-gerlach, broonie, devicetree, Viresh Kumar
In-Reply-To: <cover.1480401041.git.viresh.kumar@linaro.org>
Pass the entire supply structure instead of all of its fields.
Signed-off-by: Viresh Kumar <viresh.kumar@linaro.org>
Tested-by: Dave Gerlach <d-gerlach@ti.com>
Reviewed-by: Stephen Boyd <sboyd@codeaurora.org>
---
drivers/base/power/opp/core.c | 44 +++++++++++++++++--------------------------
1 file changed, 17 insertions(+), 27 deletions(-)
diff --git a/drivers/base/power/opp/core.c b/drivers/base/power/opp/core.c
index 8d6006151c9a..37fad2eb0f47 100644
--- a/drivers/base/power/opp/core.c
+++ b/drivers/base/power/opp/core.c
@@ -542,8 +542,7 @@ static struct clk *_get_opp_clk(struct device *dev)
}
static int _set_opp_voltage(struct device *dev, struct regulator *reg,
- unsigned long u_volt, unsigned long u_volt_min,
- unsigned long u_volt_max)
+ struct dev_pm_opp_supply *supply)
{
int ret;
@@ -554,14 +553,15 @@ static int _set_opp_voltage(struct device *dev, struct regulator *reg,
return 0;
}
- dev_dbg(dev, "%s: voltages (mV): %lu %lu %lu\n", __func__, u_volt_min,
- u_volt, u_volt_max);
+ dev_dbg(dev, "%s: voltages (mV): %lu %lu %lu\n", __func__,
+ supply->u_volt_min, supply->u_volt, supply->u_volt_max);
- ret = regulator_set_voltage_triplet(reg, u_volt_min, u_volt,
- u_volt_max);
+ ret = regulator_set_voltage_triplet(reg, supply->u_volt_min,
+ supply->u_volt, supply->u_volt_max);
if (ret)
dev_err(dev, "%s: failed to set voltage (%lu %lu %lu mV): %d\n",
- __func__, u_volt_min, u_volt, u_volt_max, ret);
+ __func__, supply->u_volt_min, supply->u_volt,
+ supply->u_volt_max, ret);
return ret;
}
@@ -583,8 +583,7 @@ int dev_pm_opp_set_rate(struct device *dev, unsigned long target_freq)
struct regulator *reg;
struct clk *clk;
unsigned long freq, old_freq;
- unsigned long u_volt, u_volt_min, u_volt_max;
- unsigned long old_u_volt, old_u_volt_min, old_u_volt_max;
+ struct dev_pm_opp_supply old_supply, new_supply;
int ret;
if (unlikely(!target_freq)) {
@@ -634,17 +633,12 @@ int dev_pm_opp_set_rate(struct device *dev, unsigned long target_freq)
return ret;
}
- if (IS_ERR(old_opp)) {
- old_u_volt = 0;
- } else {
- old_u_volt = old_opp->supply.u_volt;
- old_u_volt_min = old_opp->supply.u_volt_min;
- old_u_volt_max = old_opp->supply.u_volt_max;
- }
+ if (IS_ERR(old_opp))
+ old_supply.u_volt = 0;
+ else
+ memcpy(&old_supply, &old_opp->supply, sizeof(old_supply));
- u_volt = opp->supply.u_volt;
- u_volt_min = opp->supply.u_volt_min;
- u_volt_max = opp->supply.u_volt_max;
+ memcpy(&new_supply, &opp->supply, sizeof(new_supply));
reg = opp_table->regulator;
@@ -652,8 +646,7 @@ int dev_pm_opp_set_rate(struct device *dev, unsigned long target_freq)
/* Scaling up? Scale voltage before frequency */
if (freq > old_freq) {
- ret = _set_opp_voltage(dev, reg, u_volt, u_volt_min,
- u_volt_max);
+ ret = _set_opp_voltage(dev, reg, &new_supply);
if (ret)
goto restore_voltage;
}
@@ -672,8 +665,7 @@ int dev_pm_opp_set_rate(struct device *dev, unsigned long target_freq)
/* Scaling down? Scale voltage after frequency */
if (freq < old_freq) {
- ret = _set_opp_voltage(dev, reg, u_volt, u_volt_min,
- u_volt_max);
+ ret = _set_opp_voltage(dev, reg, &new_supply);
if (ret)
goto restore_freq;
}
@@ -686,10 +678,8 @@ int dev_pm_opp_set_rate(struct device *dev, unsigned long target_freq)
__func__, old_freq);
restore_voltage:
/* This shouldn't harm even if the voltages weren't updated earlier */
- if (old_u_volt) {
- _set_opp_voltage(dev, reg, old_u_volt, old_u_volt_min,
- old_u_volt_max);
- }
+ if (old_supply.u_volt)
+ _set_opp_voltage(dev, reg, &old_supply);
return ret;
}
--
2.7.1.410.g6faf27b
^ permalink raw reply related
* [PATCH V5 06/10] PM / OPP: Add infrastructure to manage multiple regulators
From: Viresh Kumar @ 2016-11-29 6:36 UTC (permalink / raw)
To: Rafael Wysocki, nm-l0cyMroinI0, sboyd-sgV2jX0FEOL9JmXXK+q4OQ,
Viresh Kumar
Cc: linaro-kernel-cunTk1MwBs8s++Sfvej+rw,
linux-pm-u79uwXL29TY76Z2rM5mHXA,
linux-kernel-u79uwXL29TY76Z2rM5mHXA, Vincent Guittot,
robh-DgEjT+Ai2ygdnm+yROfE0A, d-gerlach-l0cyMroinI0,
broonie-DgEjT+Ai2ygdnm+yROfE0A, devicetree-u79uwXL29TY76Z2rM5mHXA,
Viresh Kumar
In-Reply-To: <cover.1480401041.git.viresh.kumar-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org>
This patch adds infrastructure to manage multiple regulators and updates
the only user (cpufreq-dt) of dev_pm_opp_set{put}_regulator().
This is preparatory work for adding full support for devices with
multiple regulators.
Signed-off-by: Viresh Kumar <viresh.kumar-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org>
Tested-by: Dave Gerlach <d-gerlach-l0cyMroinI0@public.gmane.org>
---
V4->V5:
- Don't allocate from within rcu locked section.
- s/+//
---
drivers/base/power/opp/core.c | 246 +++++++++++++++++++++++++++------------
drivers/base/power/opp/debugfs.c | 52 +++++++--
drivers/base/power/opp/of.c | 103 +++++++++++-----
drivers/base/power/opp/opp.h | 10 +-
drivers/cpufreq/cpufreq-dt.c | 9 +-
include/linux/pm_opp.h | 8 +-
6 files changed, 301 insertions(+), 127 deletions(-)
diff --git a/drivers/base/power/opp/core.c b/drivers/base/power/opp/core.c
index 37fad2eb0f47..89a3fd720724 100644
--- a/drivers/base/power/opp/core.c
+++ b/drivers/base/power/opp/core.c
@@ -93,6 +93,8 @@ struct opp_table *_find_opp_table(struct device *dev)
* Return: voltage in micro volt corresponding to the opp, else
* return 0
*
+ * This is useful only for devices with single power supply.
+ *
* Locking: This function must be called under rcu_read_lock(). opp is a rcu
* protected pointer. This means that opp which could have been fetched by
* opp_find_freq_{exact,ceil,floor} functions is valid as long as we are
@@ -112,7 +114,7 @@ unsigned long dev_pm_opp_get_voltage(struct dev_pm_opp *opp)
if (IS_ERR_OR_NULL(tmp_opp))
pr_err("%s: Invalid parameters\n", __func__);
else
- v = tmp_opp->supply.u_volt;
+ v = tmp_opp->supplies[0].u_volt;
return v;
}
@@ -210,6 +212,24 @@ unsigned long dev_pm_opp_get_max_clock_latency(struct device *dev)
}
EXPORT_SYMBOL_GPL(dev_pm_opp_get_max_clock_latency);
+static int _get_regulator_count(struct device *dev)
+{
+ struct opp_table *opp_table;
+ int count;
+
+ rcu_read_lock();
+
+ opp_table = _find_opp_table(dev);
+ if (!IS_ERR(opp_table))
+ count = opp_table->regulator_count;
+ else
+ count = 0;
+
+ rcu_read_unlock();
+
+ return count;
+}
+
/**
* dev_pm_opp_get_max_volt_latency() - Get max voltage latency in nanoseconds
* @dev: device for which we do this operation
@@ -222,34 +242,51 @@ unsigned long dev_pm_opp_get_max_volt_latency(struct device *dev)
{
struct opp_table *opp_table;
struct dev_pm_opp *opp;
- struct regulator *reg;
+ struct regulator *reg, **regulators;
unsigned long latency_ns = 0;
- unsigned long min_uV = ~0, max_uV = 0;
- int ret;
+ int ret, i, count;
+ struct {
+ unsigned long min;
+ unsigned long max;
+ } *uV;
+
+ count = _get_regulator_count(dev);
+
+ /* Regulator may not be required for the device */
+ if (!count)
+ return 0;
+
+ regulators = kmalloc_array(count, sizeof(*regulators), GFP_KERNEL);
+ if (!regulators)
+ return 0;
+
+ uV = kmalloc_array(count, sizeof(*uV), GFP_KERNEL);
+ if (!uV)
+ goto free_regulators;
rcu_read_lock();
opp_table = _find_opp_table(dev);
if (IS_ERR(opp_table)) {
rcu_read_unlock();
- return 0;
+ goto free_uV;
}
- reg = opp_table->regulator;
- if (IS_ERR(reg)) {
- /* Regulator may not be required for device */
- rcu_read_unlock();
- return 0;
- }
+ memcpy(regulators, opp_table->regulators, count * sizeof(*regulators));
- list_for_each_entry_rcu(opp, &opp_table->opp_list, node) {
- if (!opp->available)
- continue;
+ for (i = 0; i < count; i++) {
+ uV[i].min = ~0;
+ uV[i].max = 0;
- if (opp->supply.u_volt_min < min_uV)
- min_uV = opp->supply.u_volt_min;
- if (opp->supply.u_volt_max > max_uV)
- max_uV = opp->supply.u_volt_max;
+ list_for_each_entry_rcu(opp, &opp_table->opp_list, node) {
+ if (!opp->available)
+ continue;
+
+ if (opp->supplies[i].u_volt_min < uV[i].min)
+ uV[i].min = opp->supplies[i].u_volt_min;
+ if (opp->supplies[i].u_volt_max > uV[i].max)
+ uV[i].max = opp->supplies[i].u_volt_max;
+ }
}
rcu_read_unlock();
@@ -258,9 +295,16 @@ unsigned long dev_pm_opp_get_max_volt_latency(struct device *dev)
* The caller needs to ensure that opp_table (and hence the regulator)
* isn't freed, while we are executing this routine.
*/
- ret = regulator_set_voltage_time(reg, min_uV, max_uV);
- if (ret > 0)
- latency_ns = ret * 1000;
+ for (i = 0; reg = regulators[i], i < count; i++) {
+ ret = regulator_set_voltage_time(reg, uV[i].min, uV[i].max);
+ if (ret > 0)
+ latency_ns += ret * 1000;
+ }
+
+free_uV:
+ kfree(uV);
+free_regulators:
+ kfree(regulators);
return latency_ns;
}
@@ -580,7 +624,7 @@ int dev_pm_opp_set_rate(struct device *dev, unsigned long target_freq)
{
struct opp_table *opp_table;
struct dev_pm_opp *old_opp, *opp;
- struct regulator *reg;
+ struct regulator *reg = ERR_PTR(-ENXIO);
struct clk *clk;
unsigned long freq, old_freq;
struct dev_pm_opp_supply old_supply, new_supply;
@@ -633,14 +677,23 @@ int dev_pm_opp_set_rate(struct device *dev, unsigned long target_freq)
return ret;
}
+ if (opp_table->regulators) {
+ /* This function only supports single regulator per device */
+ if (WARN_ON(opp_table->regulator_count > 1)) {
+ dev_err(dev, "multiple regulators not supported\n");
+ rcu_read_unlock();
+ return -EINVAL;
+ }
+
+ reg = opp_table->regulators[0];
+ }
+
if (IS_ERR(old_opp))
old_supply.u_volt = 0;
else
- memcpy(&old_supply, &old_opp->supply, sizeof(old_supply));
-
- memcpy(&new_supply, &opp->supply, sizeof(new_supply));
+ memcpy(&old_supply, old_opp->supplies, sizeof(old_supply));
- reg = opp_table->regulator;
+ memcpy(&new_supply, opp->supplies, sizeof(new_supply));
rcu_read_unlock();
@@ -764,9 +817,6 @@ static struct opp_table *_add_opp_table(struct device *dev)
_of_init_opp_table(opp_table, dev);
- /* Set regulator to a non-NULL error value */
- opp_table->regulator = ERR_PTR(-ENXIO);
-
/* Find clk for the device */
opp_table->clk = clk_get(dev, NULL);
if (IS_ERR(opp_table->clk)) {
@@ -815,7 +865,7 @@ static void _remove_opp_table(struct opp_table *opp_table)
if (opp_table->prop_name)
return;
- if (!IS_ERR(opp_table->regulator))
+ if (opp_table->regulators)
return;
/* Release clk */
@@ -924,35 +974,50 @@ struct dev_pm_opp *_allocate_opp(struct device *dev,
struct opp_table **opp_table)
{
struct dev_pm_opp *opp;
+ int count, supply_size;
+ struct opp_table *table;
- /* allocate new OPP node */
- opp = kzalloc(sizeof(*opp), GFP_KERNEL);
- if (!opp)
+ table = _add_opp_table(dev);
+ if (!table)
return NULL;
- INIT_LIST_HEAD(&opp->node);
+ /* Allocate space for at least one supply */
+ count = table->regulator_count ? table->regulator_count : 1;
+ supply_size = sizeof(*opp->supplies) * count;
- *opp_table = _add_opp_table(dev);
- if (!*opp_table) {
- kfree(opp);
+ /* allocate new OPP node and supplies structures */
+ opp = kzalloc(sizeof(*opp) + supply_size, GFP_KERNEL);
+ if (!opp) {
+ kfree(table);
return NULL;
}
+ /* Put the supplies at the end of the OPP structure as an empty array */
+ opp->supplies = (struct dev_pm_opp_supply *)(opp + 1);
+ INIT_LIST_HEAD(&opp->node);
+
+ *opp_table = table;
+
return opp;
}
static bool _opp_supported_by_regulators(struct dev_pm_opp *opp,
struct opp_table *opp_table)
{
- struct regulator *reg = opp_table->regulator;
-
- if (!IS_ERR(reg) &&
- !regulator_is_supported_voltage(reg, opp->supply.u_volt_min,
- opp->supply.u_volt_max)) {
- pr_warn("%s: OPP minuV: %lu maxuV: %lu, not supported by regulator\n",
- __func__, opp->supply.u_volt_min,
- opp->supply.u_volt_max);
- return false;
+ struct regulator *reg;
+ int i;
+
+ for (i = 0; i < opp_table->regulator_count; i++) {
+ reg = opp_table->regulators[i];
+
+ if (!regulator_is_supported_voltage(reg,
+ opp->supplies[i].u_volt_min,
+ opp->supplies[i].u_volt_max)) {
+ pr_warn("%s: OPP minuV: %lu maxuV: %lu, not supported by regulator\n",
+ __func__, opp->supplies[i].u_volt_min,
+ opp->supplies[i].u_volt_max);
+ return false;
+ }
}
return true;
@@ -984,12 +1049,13 @@ int _opp_add(struct device *dev, struct dev_pm_opp *new_opp,
/* Duplicate OPPs */
dev_warn(dev, "%s: duplicate OPPs detected. Existing: freq: %lu, volt: %lu, enabled: %d. New: freq: %lu, volt: %lu, enabled: %d\n",
- __func__, opp->rate, opp->supply.u_volt,
- opp->available, new_opp->rate, new_opp->supply.u_volt,
- new_opp->available);
+ __func__, opp->rate, opp->supplies[0].u_volt,
+ opp->available, new_opp->rate,
+ new_opp->supplies[0].u_volt, new_opp->available);
+ /* Should we compare voltages for all regulators here ? */
return opp->available &&
- new_opp->supply.u_volt == opp->supply.u_volt ? 0 : -EEXIST;
+ new_opp->supplies[0].u_volt == opp->supplies[0].u_volt ? 0 : -EEXIST;
}
new_opp->opp_table = opp_table;
@@ -1056,9 +1122,9 @@ int _opp_add_v1(struct device *dev, unsigned long freq, long u_volt,
/* populate the opp table */
new_opp->rate = freq;
tol = u_volt * opp_table->voltage_tolerance_v1 / 100;
- new_opp->supply.u_volt = u_volt;
- new_opp->supply.u_volt_min = u_volt - tol;
- new_opp->supply.u_volt_max = u_volt + tol;
+ new_opp->supplies[0].u_volt = u_volt;
+ new_opp->supplies[0].u_volt_min = u_volt - tol;
+ new_opp->supplies[0].u_volt_max = u_volt + tol;
new_opp->available = true;
new_opp->dynamic = dynamic;
@@ -1303,12 +1369,14 @@ void dev_pm_opp_put_prop_name(struct device *dev)
EXPORT_SYMBOL_GPL(dev_pm_opp_put_prop_name);
/**
- * dev_pm_opp_set_regulator() - Set regulator name for the device
+ * dev_pm_opp_set_regulators() - Set regulator names for the device
* @dev: Device for which regulator name is being set.
- * @name: Name of the regulator.
+ * @names: Array of pointers to the names of the regulator.
+ * @count: Number of regulators.
*
* In order to support OPP switching, OPP layer needs to know the name of the
- * device's regulator, as the core would be required to switch voltages as well.
+ * device's regulators, as the core would be required to switch voltages as
+ * well.
*
* This must be called before any OPPs are initialized for the device.
*
@@ -1318,11 +1386,12 @@ EXPORT_SYMBOL_GPL(dev_pm_opp_put_prop_name);
* that this function is *NOT* called under RCU protection or in contexts where
* mutex cannot be locked.
*/
-int dev_pm_opp_set_regulator(struct device *dev, const char *name)
+int dev_pm_opp_set_regulators(struct device *dev, const char * const names[],
+ unsigned int count)
{
struct opp_table *opp_table;
struct regulator *reg;
- int ret;
+ int ret, i;
mutex_lock(&opp_table_lock);
@@ -1338,26 +1407,44 @@ int dev_pm_opp_set_regulator(struct device *dev, const char *name)
goto err;
}
- /* Already have a regulator set */
- if (WARN_ON(!IS_ERR(opp_table->regulator))) {
+ /* Already have regulators set */
+ if (WARN_ON(opp_table->regulators)) {
ret = -EBUSY;
goto err;
}
- /* Allocate the regulator */
- reg = regulator_get_optional(dev, name);
- if (IS_ERR(reg)) {
- ret = PTR_ERR(reg);
- if (ret != -EPROBE_DEFER)
- dev_err(dev, "%s: no regulator (%s) found: %d\n",
- __func__, name, ret);
+
+ opp_table->regulators = kmalloc_array(count,
+ sizeof(*opp_table->regulators),
+ GFP_KERNEL);
+ if (!opp_table->regulators) {
+ ret = -ENOMEM;
goto err;
}
- opp_table->regulator = reg;
+ for (i = 0; i < count; i++) {
+ reg = regulator_get_optional(dev, names[i]);
+ if (IS_ERR(reg)) {
+ ret = PTR_ERR(reg);
+ if (ret != -EPROBE_DEFER)
+ dev_err(dev, "%s: regulator (%s) not found: %d\n",
+ __func__, names[i], ret);
+ goto free_regulators;
+ }
+
+ opp_table->regulators[i] = reg;
+ }
+
+ opp_table->regulator_count = count;
mutex_unlock(&opp_table_lock);
return 0;
+free_regulators:
+ while (i != 0)
+ regulator_put(opp_table->regulators[--i]);
+
+ kfree(opp_table->regulators);
+ opp_table->regulators = NULL;
err:
_remove_opp_table(opp_table);
unlock:
@@ -1365,11 +1452,11 @@ int dev_pm_opp_set_regulator(struct device *dev, const char *name)
return ret;
}
-EXPORT_SYMBOL_GPL(dev_pm_opp_set_regulator);
+EXPORT_SYMBOL_GPL(dev_pm_opp_set_regulators);
/**
- * dev_pm_opp_put_regulator() - Releases resources blocked for regulator
- * @dev: Device for which regulator was set.
+ * dev_pm_opp_put_regulators() - Releases resources blocked for regulators
+ * @dev: Device for which regulators were set.
*
* Locking: The internal opp_table and opp structures are RCU protected.
* Hence this function internally uses RCU updater strategy with mutex locks
@@ -1377,9 +1464,10 @@ EXPORT_SYMBOL_GPL(dev_pm_opp_set_regulator);
* that this function is *NOT* called under RCU protection or in contexts where
* mutex cannot be locked.
*/
-void dev_pm_opp_put_regulator(struct device *dev)
+void dev_pm_opp_put_regulators(struct device *dev)
{
struct opp_table *opp_table;
+ int i;
mutex_lock(&opp_table_lock);
@@ -1391,16 +1479,20 @@ void dev_pm_opp_put_regulator(struct device *dev)
goto unlock;
}
- if (IS_ERR(opp_table->regulator)) {
- dev_err(dev, "%s: Doesn't have regulator set\n", __func__);
+ if (!opp_table->regulators) {
+ dev_err(dev, "%s: Doesn't have regulators set\n", __func__);
goto unlock;
}
/* Make sure there are no concurrent readers while updating opp_table */
WARN_ON(!list_empty(&opp_table->opp_list));
- regulator_put(opp_table->regulator);
- opp_table->regulator = ERR_PTR(-ENXIO);
+ for (i = opp_table->regulator_count - 1; i >= 0; i--)
+ regulator_put(opp_table->regulators[i]);
+
+ kfree(opp_table->regulators);
+ opp_table->regulators = NULL;
+ opp_table->regulator_count = 0;
/* Try freeing opp_table if this was the last blocking resource */
_remove_opp_table(opp_table);
@@ -1408,7 +1500,7 @@ void dev_pm_opp_put_regulator(struct device *dev)
unlock:
mutex_unlock(&opp_table_lock);
}
-EXPORT_SYMBOL_GPL(dev_pm_opp_put_regulator);
+EXPORT_SYMBOL_GPL(dev_pm_opp_put_regulators);
/**
* dev_pm_opp_add() - Add an OPP table from a table definitions
diff --git a/drivers/base/power/opp/debugfs.c b/drivers/base/power/opp/debugfs.c
index c897676ca35f..95f433db4ac7 100644
--- a/drivers/base/power/opp/debugfs.c
+++ b/drivers/base/power/opp/debugfs.c
@@ -15,6 +15,7 @@
#include <linux/err.h>
#include <linux/init.h>
#include <linux/limits.h>
+#include <linux/slab.h>
#include "opp.h"
@@ -34,6 +35,46 @@ void opp_debug_remove_one(struct dev_pm_opp *opp)
debugfs_remove_recursive(opp->dentry);
}
+static bool opp_debug_create_supplies(struct dev_pm_opp *opp,
+ struct opp_table *opp_table,
+ struct dentry *pdentry)
+{
+ struct dentry *d;
+ int i = 0;
+ char *name;
+
+ /* Always create at least supply-0 directory */
+ do {
+ name = kasprintf(GFP_KERNEL, "supply-%d", i);
+
+ /* Create per-opp directory */
+ d = debugfs_create_dir(name, pdentry);
+
+ kfree(name);
+
+ if (!d)
+ return false;
+
+ if (!debugfs_create_ulong("u_volt_target", S_IRUGO, d,
+ &opp->supplies[i].u_volt))
+ return false;
+
+ if (!debugfs_create_ulong("u_volt_min", S_IRUGO, d,
+ &opp->supplies[i].u_volt_min))
+ return false;
+
+ if (!debugfs_create_ulong("u_volt_max", S_IRUGO, d,
+ &opp->supplies[i].u_volt_max))
+ return false;
+
+ if (!debugfs_create_ulong("u_amp", S_IRUGO, d,
+ &opp->supplies[i].u_amp))
+ return false;
+ } while (++i < opp_table->regulator_count);
+
+ return true;
+}
+
int opp_debug_create_one(struct dev_pm_opp *opp, struct opp_table *opp_table)
{
struct dentry *pdentry = opp_table->dentry;
@@ -63,16 +104,7 @@ int opp_debug_create_one(struct dev_pm_opp *opp, struct opp_table *opp_table)
if (!debugfs_create_ulong("rate_hz", S_IRUGO, d, &opp->rate))
return -ENOMEM;
- if (!debugfs_create_ulong("u_volt_target", S_IRUGO, d, &opp->supply.u_volt))
- return -ENOMEM;
-
- if (!debugfs_create_ulong("u_volt_min", S_IRUGO, d, &opp->supply.u_volt_min))
- return -ENOMEM;
-
- if (!debugfs_create_ulong("u_volt_max", S_IRUGO, d, &opp->supply.u_volt_max))
- return -ENOMEM;
-
- if (!debugfs_create_ulong("u_amp", S_IRUGO, d, &opp->supply.u_amp))
+ if (!opp_debug_create_supplies(opp, opp_table, d))
return -ENOMEM;
if (!debugfs_create_ulong("clock_latency_ns", S_IRUGO, d,
diff --git a/drivers/base/power/opp/of.c b/drivers/base/power/opp/of.c
index bdf409d42126..3f7d2591b173 100644
--- a/drivers/base/power/opp/of.c
+++ b/drivers/base/power/opp/of.c
@@ -17,6 +17,7 @@
#include <linux/errno.h>
#include <linux/device.h>
#include <linux/of.h>
+#include <linux/slab.h>
#include <linux/export.h>
#include "opp.h"
@@ -101,16 +102,16 @@ static bool _opp_is_supported(struct device *dev, struct opp_table *opp_table,
return true;
}
-/* TODO: Support multiple regulators */
static int opp_parse_supplies(struct dev_pm_opp *opp, struct device *dev,
struct opp_table *opp_table)
{
- u32 microvolt[3] = {0};
- u32 val;
- int count, ret;
+ u32 *microvolt, *microamp = NULL;
+ int supplies, vcount, icount, ret, i, j;
struct property *prop = NULL;
char name[NAME_MAX];
+ supplies = opp_table->regulator_count ? opp_table->regulator_count : 1;
+
/* Search for "opp-microvolt-<name>" */
if (opp_table->prop_name) {
snprintf(name, sizeof(name), "opp-microvolt-%s",
@@ -128,34 +129,29 @@ static int opp_parse_supplies(struct dev_pm_opp *opp, struct device *dev,
return 0;
}
- count = of_property_count_u32_elems(opp->np, name);
- if (count < 0) {
+ vcount = of_property_count_u32_elems(opp->np, name);
+ if (vcount < 0) {
dev_err(dev, "%s: Invalid %s property (%d)\n",
- __func__, name, count);
- return count;
+ __func__, name, vcount);
+ return vcount;
}
- /* There can be one or three elements here */
- if (count != 1 && count != 3) {
- dev_err(dev, "%s: Invalid number of elements in %s property (%d)\n",
- __func__, name, count);
+ /* There can be one or three elements per supply */
+ if (vcount != supplies && vcount != supplies * 3) {
+ dev_err(dev, "%s: Invalid number of elements in %s property (%d) with supplies (%d)\n",
+ __func__, name, vcount, supplies);
return -EINVAL;
}
- ret = of_property_read_u32_array(opp->np, name, microvolt, count);
+ microvolt = kmalloc_array(vcount, sizeof(*microvolt), GFP_KERNEL);
+ if (!microvolt)
+ return -ENOMEM;
+
+ ret = of_property_read_u32_array(opp->np, name, microvolt, vcount);
if (ret) {
dev_err(dev, "%s: error parsing %s: %d\n", __func__, name, ret);
- return -EINVAL;
- }
-
- opp->supply.u_volt = microvolt[0];
-
- if (count == 1) {
- opp->supply.u_volt_min = opp->supply.u_volt;
- opp->supply.u_volt_max = opp->supply.u_volt;
- } else {
- opp->supply.u_volt_min = microvolt[1];
- opp->supply.u_volt_max = microvolt[2];
+ ret = -EINVAL;
+ goto free_microvolt;
}
/* Search for "opp-microamp-<name>" */
@@ -172,10 +168,59 @@ static int opp_parse_supplies(struct dev_pm_opp *opp, struct device *dev,
prop = of_find_property(opp->np, name, NULL);
}
- if (prop && !of_property_read_u32(opp->np, name, &val))
- opp->supply.u_amp = val;
+ if (prop) {
+ icount = of_property_count_u32_elems(opp->np, name);
+ if (icount < 0) {
+ dev_err(dev, "%s: Invalid %s property (%d)\n", __func__,
+ name, icount);
+ ret = icount;
+ goto free_microvolt;
+ }
- return 0;
+ if (icount != supplies) {
+ dev_err(dev, "%s: Invalid number of elements in %s property (%d) with supplies (%d)\n",
+ __func__, name, icount, supplies);
+ ret = -EINVAL;
+ goto free_microvolt;
+ }
+
+ microamp = kmalloc_array(icount, sizeof(*microamp), GFP_KERNEL);
+ if (!microamp) {
+ ret = -EINVAL;
+ goto free_microvolt;
+ }
+
+ ret = of_property_read_u32_array(opp->np, name, microamp,
+ icount);
+ if (ret) {
+ dev_err(dev, "%s: error parsing %s: %d\n", __func__,
+ name, ret);
+ ret = -EINVAL;
+ goto free_microamp;
+ }
+ }
+
+ for (i = 0, j = 0; i < supplies; i++) {
+ opp->supplies[i].u_volt = microvolt[j++];
+
+ if (vcount == supplies) {
+ opp->supplies[i].u_volt_min = opp->supplies[i].u_volt;
+ opp->supplies[i].u_volt_max = opp->supplies[i].u_volt;
+ } else {
+ opp->supplies[i].u_volt_min = microvolt[j++];
+ opp->supplies[i].u_volt_max = microvolt[j++];
+ }
+
+ if (microamp)
+ opp->supplies[i].u_amp = microamp[i];
+ }
+
+free_microamp:
+ kfree(microamp);
+free_microvolt:
+ kfree(microvolt);
+
+ return ret;
}
/**
@@ -304,8 +349,8 @@ static int _opp_add_static_v2(struct device *dev, struct device_node *np)
pr_debug("%s: turbo:%d rate:%lu uv:%lu uvmin:%lu uvmax:%lu latency:%lu\n",
__func__, new_opp->turbo, new_opp->rate,
- new_opp->supply.u_volt, new_opp->supply.u_volt_min,
- new_opp->supply.u_volt_max, new_opp->clock_latency_ns);
+ new_opp->supplies[0].u_volt, new_opp->supplies[0].u_volt_min,
+ new_opp->supplies[0].u_volt_max, new_opp->clock_latency_ns);
/*
* Notify the changes in the availability of the operable
diff --git a/drivers/base/power/opp/opp.h b/drivers/base/power/opp/opp.h
index 8a02516542c2..5b0f7e53bede 100644
--- a/drivers/base/power/opp/opp.h
+++ b/drivers/base/power/opp/opp.h
@@ -61,7 +61,7 @@ extern struct list_head opp_tables;
* @turbo: true if turbo (boost) OPP
* @suspend: true if suspend OPP
* @rate: Frequency in hertz
- * @supply: Power supply voltage/current values
+ * @supplies: Power supplies voltage/current values
* @clock_latency_ns: Latency (in nanoseconds) of switching to this OPP's
* frequency from any other OPP's frequency.
* @opp_table: points back to the opp_table struct this opp belongs to
@@ -80,7 +80,7 @@ struct dev_pm_opp {
bool suspend;
unsigned long rate;
- struct dev_pm_opp_supply supply;
+ struct dev_pm_opp_supply *supplies;
unsigned long clock_latency_ns;
@@ -139,7 +139,8 @@ enum opp_table_access {
* @supported_hw_count: Number of elements in supported_hw array.
* @prop_name: A name to postfix to many DT properties, while parsing them.
* @clk: Device's clock handle
- * @regulator: Supply regulator
+ * @regulators: Supply regulators
+ * @regulator_count: Number of power supply regulators
* @dentry: debugfs dentry pointer of the real device directory (not links).
* @dentry_name: Name of the real dentry.
*
@@ -174,7 +175,8 @@ struct opp_table {
unsigned int supported_hw_count;
const char *prop_name;
struct clk *clk;
- struct regulator *regulator;
+ struct regulator **regulators;
+ unsigned int regulator_count;
#ifdef CONFIG_DEBUG_FS
struct dentry *dentry;
diff --git a/drivers/cpufreq/cpufreq-dt.c b/drivers/cpufreq/cpufreq-dt.c
index 5c07ae05d69a..15cb26118dc7 100644
--- a/drivers/cpufreq/cpufreq-dt.c
+++ b/drivers/cpufreq/cpufreq-dt.c
@@ -186,7 +186,10 @@ static int cpufreq_init(struct cpufreq_policy *policy)
*/
name = find_supply_name(cpu_dev);
if (name) {
- ret = dev_pm_opp_set_regulator(cpu_dev, name);
+ const char *names[] = {name};
+
+ ret = dev_pm_opp_set_regulators(cpu_dev, names,
+ ARRAY_SIZE(names));
if (ret) {
dev_err(cpu_dev, "Failed to set regulator for cpu%d: %d\n",
policy->cpu, ret);
@@ -285,7 +288,7 @@ static int cpufreq_init(struct cpufreq_policy *policy)
out_free_opp:
dev_pm_opp_of_cpumask_remove_table(policy->cpus);
if (name)
- dev_pm_opp_put_regulator(cpu_dev);
+ dev_pm_opp_put_regulators(cpu_dev);
out_put_clk:
clk_put(cpu_clk);
@@ -300,7 +303,7 @@ static int cpufreq_exit(struct cpufreq_policy *policy)
dev_pm_opp_free_cpufreq_table(priv->cpu_dev, &policy->freq_table);
dev_pm_opp_of_cpumask_remove_table(policy->related_cpus);
if (priv->reg_name)
- dev_pm_opp_put_regulator(priv->cpu_dev);
+ dev_pm_opp_put_regulators(priv->cpu_dev);
clk_put(policy->clk);
kfree(priv);
diff --git a/include/linux/pm_opp.h b/include/linux/pm_opp.h
index f69126e2bb59..27eea9bfc5ed 100644
--- a/include/linux/pm_opp.h
+++ b/include/linux/pm_opp.h
@@ -78,8 +78,8 @@ int dev_pm_opp_set_supported_hw(struct device *dev, const u32 *versions,
void dev_pm_opp_put_supported_hw(struct device *dev);
int dev_pm_opp_set_prop_name(struct device *dev, const char *name);
void dev_pm_opp_put_prop_name(struct device *dev);
-int dev_pm_opp_set_regulator(struct device *dev, const char *name);
-void dev_pm_opp_put_regulator(struct device *dev);
+int dev_pm_opp_set_regulators(struct device *dev, const char * const names[], unsigned int count);
+void dev_pm_opp_put_regulators(struct device *dev);
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);
int dev_pm_opp_get_sharing_cpus(struct device *cpu_dev, struct cpumask *cpumask);
@@ -186,12 +186,12 @@ static inline int dev_pm_opp_set_prop_name(struct device *dev, const char *name)
static inline void dev_pm_opp_put_prop_name(struct device *dev) {}
-static inline int dev_pm_opp_set_regulator(struct device *dev, const char *name)
+static inline int dev_pm_opp_set_regulators(struct device *dev, const char *names[], unsigned int count)
{
return -ENOTSUPP;
}
-static inline void dev_pm_opp_put_regulator(struct device *dev) {}
+static inline void dev_pm_opp_put_regulators(struct device *dev) {}
static inline int dev_pm_opp_set_rate(struct device *dev, unsigned long target_freq)
{
--
2.7.1.410.g6faf27b
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply related
* [PATCH V5 07/10] PM / OPP: Separate out _generic_set_opp()
From: Viresh Kumar @ 2016-11-29 6:36 UTC (permalink / raw)
To: Rafael Wysocki, nm, sboyd, Viresh Kumar
Cc: linaro-kernel, linux-pm, linux-kernel, Vincent Guittot, robh,
d-gerlach, broonie, devicetree, Viresh Kumar
In-Reply-To: <cover.1480401041.git.viresh.kumar@linaro.org>
Later patches would add support for custom set_opp() callbacks. This
patch separates out the code for _generic_set_opp() handler in order to
prepare for that.
Signed-off-by: Viresh Kumar <viresh.kumar@linaro.org>
Tested-by: Dave Gerlach <d-gerlach@ti.com>
Reviewed-by: Stephen Boyd <sboyd@codeaurora.org>
---
V4->V5:
- Make 'dev' part of struct dev_pm_set_opp_data
- Fix commit log: s/opp_set_rate/set_opp
- Same in a comment as well
---
drivers/base/power/opp/core.c | 181 +++++++++++++++++++++++++++++-------------
drivers/base/power/opp/opp.h | 3 +
include/linux/pm_opp.h | 35 ++++++++
3 files changed, 166 insertions(+), 53 deletions(-)
diff --git a/drivers/base/power/opp/core.c b/drivers/base/power/opp/core.c
index 89a3fd720724..3a0b9d993c42 100644
--- a/drivers/base/power/opp/core.c
+++ b/drivers/base/power/opp/core.c
@@ -610,6 +610,69 @@ static int _set_opp_voltage(struct device *dev, struct regulator *reg,
return ret;
}
+static inline int
+_generic_set_opp_clk_only(struct device *dev, struct clk *clk,
+ unsigned long old_freq, unsigned long freq)
+{
+ int ret;
+
+ ret = clk_set_rate(clk, freq);
+ if (ret) {
+ dev_err(dev, "%s: failed to set clock rate: %d\n", __func__,
+ ret);
+ }
+
+ return ret;
+}
+
+static int _generic_set_opp(struct dev_pm_set_opp_data *data)
+{
+ struct dev_pm_opp_supply *old_supply = data->old_opp.supplies;
+ struct dev_pm_opp_supply *new_supply = data->new_opp.supplies;
+ unsigned long old_freq = data->old_opp.rate, freq = data->new_opp.rate;
+ struct regulator *reg = data->regulators[0];
+ struct device *dev= data->dev;
+ int ret;
+
+ /* This function only supports single regulator per device */
+ if (WARN_ON(data->regulator_count > 1)) {
+ dev_err(dev, "multiple regulators are not supported\n");
+ return -EINVAL;
+ }
+
+ /* Scaling up? Scale voltage before frequency */
+ if (freq > old_freq) {
+ ret = _set_opp_voltage(dev, reg, new_supply);
+ if (ret)
+ goto restore_voltage;
+ }
+
+ /* Change frequency */
+ ret = _generic_set_opp_clk_only(dev, data->clk, old_freq, freq);
+ if (ret)
+ goto restore_voltage;
+
+ /* Scaling down? Scale voltage after frequency */
+ if (freq < old_freq) {
+ ret = _set_opp_voltage(dev, reg, new_supply);
+ if (ret)
+ goto restore_freq;
+ }
+
+ return 0;
+
+restore_freq:
+ if (_generic_set_opp_clk_only(dev, data->clk, freq, old_freq))
+ dev_err(dev, "%s: failed to restore old-freq (%lu Hz)\n",
+ __func__, old_freq);
+restore_voltage:
+ /* This shouldn't harm even if the voltages weren't updated earlier */
+ if (old_supply->u_volt)
+ _set_opp_voltage(dev, reg, old_supply);
+
+ return ret;
+}
+
/**
* dev_pm_opp_set_rate() - Configure new OPP based on frequency
* @dev: device for which we do this operation
@@ -623,12 +686,12 @@ static int _set_opp_voltage(struct device *dev, struct regulator *reg,
int dev_pm_opp_set_rate(struct device *dev, unsigned long target_freq)
{
struct opp_table *opp_table;
+ unsigned long freq, old_freq;
struct dev_pm_opp *old_opp, *opp;
- struct regulator *reg = ERR_PTR(-ENXIO);
+ struct regulator **regulators;
+ struct dev_pm_set_opp_data *data;
struct clk *clk;
- unsigned long freq, old_freq;
- struct dev_pm_opp_supply old_supply, new_supply;
- int ret;
+ int ret, size;
if (unlikely(!target_freq)) {
dev_err(dev, "%s: Invalid target frequency %lu\n", __func__,
@@ -677,64 +740,36 @@ int dev_pm_opp_set_rate(struct device *dev, unsigned long target_freq)
return ret;
}
- if (opp_table->regulators) {
- /* This function only supports single regulator per device */
- if (WARN_ON(opp_table->regulator_count > 1)) {
- dev_err(dev, "multiple regulators not supported\n");
- rcu_read_unlock();
- return -EINVAL;
- }
+ dev_dbg(dev, "%s: switching OPP: %lu Hz --> %lu Hz\n", __func__,
+ old_freq, freq);
- reg = opp_table->regulators[0];
+ regulators = opp_table->regulators;
+
+ /* Only frequency scaling */
+ if (!regulators) {
+ rcu_read_unlock();
+ return _generic_set_opp_clk_only(dev, clk, old_freq, freq);
}
+ data = opp_table->set_opp_data;
+ data->regulators = regulators;
+ data->regulator_count = opp_table->regulator_count;
+ data->clk = clk;
+ data->dev = dev;
+
+ data->old_opp.rate = old_freq;
+ size = sizeof(*opp->supplies) * opp_table->regulator_count;
if (IS_ERR(old_opp))
- old_supply.u_volt = 0;
+ memset(data->old_opp.supplies, 0, size);
else
- memcpy(&old_supply, old_opp->supplies, sizeof(old_supply));
+ memcpy(data->old_opp.supplies, old_opp->supplies, size);
- memcpy(&new_supply, opp->supplies, sizeof(new_supply));
+ data->new_opp.rate = freq;
+ memcpy(data->new_opp.supplies, opp->supplies, size);
rcu_read_unlock();
- /* Scaling up? Scale voltage before frequency */
- if (freq > old_freq) {
- ret = _set_opp_voltage(dev, reg, &new_supply);
- if (ret)
- goto restore_voltage;
- }
-
- /* Change frequency */
-
- dev_dbg(dev, "%s: switching OPP: %lu Hz --> %lu Hz\n",
- __func__, old_freq, freq);
-
- ret = clk_set_rate(clk, freq);
- if (ret) {
- dev_err(dev, "%s: failed to set clock rate: %d\n", __func__,
- ret);
- goto restore_voltage;
- }
-
- /* Scaling down? Scale voltage after frequency */
- if (freq < old_freq) {
- ret = _set_opp_voltage(dev, reg, &new_supply);
- if (ret)
- goto restore_freq;
- }
-
- return 0;
-
-restore_freq:
- if (clk_set_rate(clk, old_freq))
- dev_err(dev, "%s: failed to restore old-freq (%lu Hz)\n",
- __func__, old_freq);
-restore_voltage:
- /* This shouldn't harm even if the voltages weren't updated earlier */
- if (old_supply.u_volt)
- _set_opp_voltage(dev, reg, &old_supply);
-
- return ret;
+ return _generic_set_opp(data);
}
EXPORT_SYMBOL_GPL(dev_pm_opp_set_rate);
@@ -1368,6 +1403,38 @@ void dev_pm_opp_put_prop_name(struct device *dev)
}
EXPORT_SYMBOL_GPL(dev_pm_opp_put_prop_name);
+static int _allocate_set_opp_data(struct opp_table *opp_table)
+{
+ struct dev_pm_set_opp_data *data;
+ int len, count = opp_table->regulator_count;
+
+ if (WARN_ON(!count))
+ return -EINVAL;
+
+ /* space for set_opp_data */
+ len = sizeof(*data);
+
+ /* space for old_opp.supplies and new_opp.supplies */
+ len += 2 * sizeof(struct dev_pm_opp_supply) * count;
+
+ data = kzalloc(len, GFP_KERNEL);
+ if (!data)
+ return -ENOMEM;
+
+ data->old_opp.supplies = (void *)(data + 1);
+ data->new_opp.supplies = data->old_opp.supplies + count;
+
+ opp_table->set_opp_data = data;
+
+ return 0;
+}
+
+static void _free_set_opp_data(struct opp_table *opp_table)
+{
+ kfree(opp_table->set_opp_data);
+ opp_table->set_opp_data = NULL;
+}
+
/**
* dev_pm_opp_set_regulators() - Set regulator names for the device
* @dev: Device for which regulator name is being set.
@@ -1436,6 +1503,11 @@ int dev_pm_opp_set_regulators(struct device *dev, const char * const names[],
opp_table->regulator_count = count;
+ /* Allocate block only once to pass to set_opp() routines */
+ ret = _allocate_set_opp_data(opp_table);
+ if (ret)
+ goto free_regulators;
+
mutex_unlock(&opp_table_lock);
return 0;
@@ -1445,6 +1517,7 @@ int dev_pm_opp_set_regulators(struct device *dev, const char * const names[],
kfree(opp_table->regulators);
opp_table->regulators = NULL;
+ opp_table->regulator_count = 0;
err:
_remove_opp_table(opp_table);
unlock:
@@ -1490,6 +1563,8 @@ void dev_pm_opp_put_regulators(struct device *dev)
for (i = opp_table->regulator_count - 1; i >= 0; i--)
regulator_put(opp_table->regulators[i]);
+ _free_set_opp_data(opp_table);
+
kfree(opp_table->regulators);
opp_table->regulators = NULL;
opp_table->regulator_count = 0;
diff --git a/drivers/base/power/opp/opp.h b/drivers/base/power/opp/opp.h
index 5b0f7e53bede..a05e43912c6b 100644
--- a/drivers/base/power/opp/opp.h
+++ b/drivers/base/power/opp/opp.h
@@ -141,6 +141,7 @@ enum opp_table_access {
* @clk: Device's clock handle
* @regulators: Supply regulators
* @regulator_count: Number of power supply regulators
+ * @set_opp_data: Data to be passed to set_opp callback
* @dentry: debugfs dentry pointer of the real device directory (not links).
* @dentry_name: Name of the real dentry.
*
@@ -178,6 +179,8 @@ struct opp_table {
struct regulator **regulators;
unsigned int regulator_count;
+ struct dev_pm_set_opp_data *set_opp_data;
+
#ifdef CONFIG_DEBUG_FS
struct dentry *dentry;
char dentry_name[NAME_MAX];
diff --git a/include/linux/pm_opp.h b/include/linux/pm_opp.h
index 27eea9bfc5ed..4723625bc16b 100644
--- a/include/linux/pm_opp.h
+++ b/include/linux/pm_opp.h
@@ -17,6 +17,8 @@
#include <linux/err.h>
#include <linux/notifier.h>
+struct clk;
+struct regulator;
struct dev_pm_opp;
struct device;
@@ -40,6 +42,39 @@ struct dev_pm_opp_supply {
unsigned long u_amp;
};
+/**
+ * struct dev_pm_opp_info - OPP freq/voltage/current values
+ * @rate: Target clk rate in hz
+ * @supplies: Array of voltage/current values for all power supplies
+ *
+ * This structure stores the freq/voltage/current values for a single OPP.
+ */
+struct dev_pm_opp_info {
+ unsigned long rate;
+ struct dev_pm_opp_supply *supplies;
+};
+
+/**
+ * struct dev_pm_set_opp_data - Set OPP data
+ * @old_opp: Old OPP info
+ * @new_opp: New OPP info
+ * @regulators: Array of regulator pointers
+ * @regulator_count: Number of regulators
+ * @clk: Pointer to clk
+ * @dev: Pointer to the struct device
+ *
+ * This structure contains all information required for setting an OPP.
+ */
+struct dev_pm_set_opp_data {
+ struct dev_pm_opp_info old_opp;
+ struct dev_pm_opp_info new_opp;
+
+ struct regulator **regulators;
+ unsigned int regulator_count;
+ struct clk *clk;
+ struct device *dev;
+};
+
#if defined(CONFIG_PM_OPP)
unsigned long dev_pm_opp_get_voltage(struct dev_pm_opp *opp);
--
2.7.1.410.g6faf27b
^ permalink raw reply related
* [PATCH V5 08/10] PM / OPP: Allow platform specific custom set_opp() callbacks
From: Viresh Kumar @ 2016-11-29 6:36 UTC (permalink / raw)
To: Rafael Wysocki, nm, sboyd, Viresh Kumar
Cc: linaro-kernel, linux-pm, linux-kernel, Vincent Guittot, robh,
d-gerlach, broonie, devicetree, Viresh Kumar
In-Reply-To: <cover.1480401041.git.viresh.kumar@linaro.org>
The generic set_opp() handler isn't sufficient for platforms with
complex DVFS. For example, some TI platforms have multiple regulators
for a CPU device. The order in which various supplies need to be
programmed is only known to the platform code and its best to leave it
to it.
This patch implements APIs to register platform specific set_opp()
callback.
Signed-off-by: Viresh Kumar <viresh.kumar@linaro.org>
Tested-by: Dave Gerlach <d-gerlach@ti.com>
---
V4->V5:
- s/custom OPP set rate/custom set OPP/
- set_opp() doesn't have a separate 'dev' argument now.
---
drivers/base/power/opp/core.c | 114 +++++++++++++++++++++++++++++++++++++++++-
drivers/base/power/opp/opp.h | 2 +
include/linux/pm_opp.h | 10 ++++
3 files changed, 125 insertions(+), 1 deletion(-)
diff --git a/drivers/base/power/opp/core.c b/drivers/base/power/opp/core.c
index 3a0b9d993c42..ddd4915ffd4f 100644
--- a/drivers/base/power/opp/core.c
+++ b/drivers/base/power/opp/core.c
@@ -687,6 +687,7 @@ int dev_pm_opp_set_rate(struct device *dev, unsigned long target_freq)
{
struct opp_table *opp_table;
unsigned long freq, old_freq;
+ int (*set_opp)(struct dev_pm_set_opp_data *data);
struct dev_pm_opp *old_opp, *opp;
struct regulator **regulators;
struct dev_pm_set_opp_data *data;
@@ -751,6 +752,11 @@ int dev_pm_opp_set_rate(struct device *dev, unsigned long target_freq)
return _generic_set_opp_clk_only(dev, clk, old_freq, freq);
}
+ if (opp_table->set_opp)
+ set_opp = opp_table->set_opp;
+ else
+ set_opp = _generic_set_opp;
+
data = opp_table->set_opp_data;
data->regulators = regulators;
data->regulator_count = opp_table->regulator_count;
@@ -769,7 +775,7 @@ int dev_pm_opp_set_rate(struct device *dev, unsigned long target_freq)
rcu_read_unlock();
- return _generic_set_opp(data);
+ return set_opp(data);
}
EXPORT_SYMBOL_GPL(dev_pm_opp_set_rate);
@@ -903,6 +909,9 @@ static void _remove_opp_table(struct opp_table *opp_table)
if (opp_table->regulators)
return;
+ if (opp_table->set_opp)
+ return;
+
/* Release clk */
if (!IS_ERR(opp_table->clk))
clk_put(opp_table->clk);
@@ -1578,6 +1587,109 @@ void dev_pm_opp_put_regulators(struct device *dev)
EXPORT_SYMBOL_GPL(dev_pm_opp_put_regulators);
/**
+ * dev_pm_opp_register_set_opp_helper() - Register custom set OPP helper
+ * @dev: Device for which the helper is getting registered.
+ * @set_opp: Custom set OPP helper.
+ *
+ * This is useful to support complex platforms (like platforms with multiple
+ * regulators per device), instead of the generic OPP set rate helper.
+ *
+ * This must be called before any OPPs are initialized for the device.
+ *
+ * Locking: The internal opp_table and opp structures are RCU protected.
+ * Hence this function internally uses RCU updater strategy with mutex locks
+ * to keep the integrity of the internal data structures. Callers should ensure
+ * that this function is *NOT* called under RCU protection or in contexts where
+ * mutex cannot be locked.
+ */
+int dev_pm_opp_register_set_opp_helper(struct device *dev,
+ int (*set_opp)(struct dev_pm_set_opp_data *data))
+{
+ struct opp_table *opp_table;
+ int ret;
+
+ if (!set_opp)
+ return -EINVAL;
+
+ mutex_lock(&opp_table_lock);
+
+ opp_table = _add_opp_table(dev);
+ if (!opp_table) {
+ ret = -ENOMEM;
+ goto unlock;
+ }
+
+ /* This should be called before OPPs are initialized */
+ if (WARN_ON(!list_empty(&opp_table->opp_list))) {
+ ret = -EBUSY;
+ goto err;
+ }
+
+ /* Already have custom set_opp helper */
+ if (WARN_ON(opp_table->set_opp)) {
+ ret = -EBUSY;
+ goto err;
+ }
+
+ opp_table->set_opp = set_opp;
+
+ mutex_unlock(&opp_table_lock);
+ return 0;
+
+err:
+ _remove_opp_table(opp_table);
+unlock:
+ mutex_unlock(&opp_table_lock);
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(dev_pm_opp_register_set_opp_helper);
+
+/**
+ * dev_pm_opp_register_put_opp_helper() - Releases resources blocked for
+ * set_opp helper
+ * @dev: Device for which custom set_opp helper has to be cleared.
+ *
+ * Locking: The internal opp_table and opp structures are RCU protected.
+ * Hence this function internally uses RCU updater strategy with mutex locks
+ * to keep the integrity of the internal data structures. Callers should ensure
+ * that this function is *NOT* called under RCU protection or in contexts where
+ * mutex cannot be locked.
+ */
+void dev_pm_opp_register_put_opp_helper(struct device *dev)
+{
+ struct opp_table *opp_table;
+
+ mutex_lock(&opp_table_lock);
+
+ /* Check for existing table for 'dev' first */
+ opp_table = _find_opp_table(dev);
+ if (IS_ERR(opp_table)) {
+ dev_err(dev, "Failed to find opp_table: %ld\n",
+ PTR_ERR(opp_table));
+ goto unlock;
+ }
+
+ if (!opp_table->set_opp) {
+ dev_err(dev, "%s: Doesn't have custom set_opp helper set\n",
+ __func__);
+ goto unlock;
+ }
+
+ /* Make sure there are no concurrent readers while updating opp_table */
+ WARN_ON(!list_empty(&opp_table->opp_list));
+
+ opp_table->set_opp = NULL;
+
+ /* Try freeing opp_table if this was the last blocking resource */
+ _remove_opp_table(opp_table);
+
+unlock:
+ mutex_unlock(&opp_table_lock);
+}
+EXPORT_SYMBOL_GPL(dev_pm_opp_register_put_opp_helper);
+
+/**
* dev_pm_opp_add() - Add an OPP table from a table definitions
* @dev: device for which we do this operation
* @freq: Frequency in Hz for this OPP
diff --git a/drivers/base/power/opp/opp.h b/drivers/base/power/opp/opp.h
index a05e43912c6b..af9f2b849a66 100644
--- a/drivers/base/power/opp/opp.h
+++ b/drivers/base/power/opp/opp.h
@@ -141,6 +141,7 @@ enum opp_table_access {
* @clk: Device's clock handle
* @regulators: Supply regulators
* @regulator_count: Number of power supply regulators
+ * @set_opp: Platform specific set_opp callback
* @set_opp_data: Data to be passed to set_opp callback
* @dentry: debugfs dentry pointer of the real device directory (not links).
* @dentry_name: Name of the real dentry.
@@ -179,6 +180,7 @@ struct opp_table {
struct regulator **regulators;
unsigned int regulator_count;
+ int (*set_opp)(struct dev_pm_set_opp_data *data);
struct dev_pm_set_opp_data *set_opp_data;
#ifdef CONFIG_DEBUG_FS
diff --git a/include/linux/pm_opp.h b/include/linux/pm_opp.h
index 4723625bc16b..d62bd05d3b1d 100644
--- a/include/linux/pm_opp.h
+++ b/include/linux/pm_opp.h
@@ -115,6 +115,8 @@ int dev_pm_opp_set_prop_name(struct device *dev, const char *name);
void dev_pm_opp_put_prop_name(struct device *dev);
int dev_pm_opp_set_regulators(struct device *dev, const char * const names[], unsigned int count);
void dev_pm_opp_put_regulators(struct device *dev);
+int dev_pm_opp_register_set_opp_helper(struct device *dev, int (*set_opp)(struct dev_pm_set_opp_data *data));
+void dev_pm_opp_register_put_opp_helper(struct device *dev);
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);
int dev_pm_opp_get_sharing_cpus(struct device *cpu_dev, struct cpumask *cpumask);
@@ -214,6 +216,14 @@ static inline int dev_pm_opp_set_supported_hw(struct device *dev,
static inline void dev_pm_opp_put_supported_hw(struct device *dev) {}
+static inline int dev_pm_opp_register_set_opp_helper(struct device *dev,
+ int (*set_opp)(struct dev_pm_set_opp_data *data))
+{
+ return -ENOTSUPP;
+}
+
+static inline void dev_pm_opp_register_put_opp_helper(struct device *dev) {}
+
static inline int dev_pm_opp_set_prop_name(struct device *dev, const char *name)
{
return -ENOTSUPP;
--
2.7.1.410.g6faf27b
^ permalink raw reply related
* [PATCH V5 09/10] PM / OPP: Don't WARN on multiple calls to dev_pm_opp_set_regulators()
From: Viresh Kumar @ 2016-11-29 6:36 UTC (permalink / raw)
To: Rafael Wysocki, nm, sboyd, Viresh Kumar
Cc: linaro-kernel, linux-pm, linux-kernel, Vincent Guittot, robh,
d-gerlach, broonie, devicetree, Viresh Kumar
In-Reply-To: <cover.1480401041.git.viresh.kumar@linaro.org>
If a platform specific OPP driver has called this routine first and set
the regulators, then the second call from cpufreq-dt driver will hit the
WARN_ON(). Remove the WARN_ON(), but continue to return error in such
cases.
Signed-off-by: Viresh Kumar <viresh.kumar@linaro.org>
Reviewed-by: Stephen Boyd <sboyd@codeaurora.org>
Tested-by: Dave Gerlach <d-gerlach@ti.com>
---
drivers/base/power/opp/core.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/base/power/opp/core.c b/drivers/base/power/opp/core.c
index ddd4915ffd4f..3c9f223709ab 100644
--- a/drivers/base/power/opp/core.c
+++ b/drivers/base/power/opp/core.c
@@ -1484,7 +1484,7 @@ int dev_pm_opp_set_regulators(struct device *dev, const char * const names[],
}
/* Already have regulators set */
- if (WARN_ON(opp_table->regulators)) {
+ if (opp_table->regulators) {
ret = -EBUSY;
goto err;
}
--
2.7.1.410.g6faf27b
^ permalink raw reply related
* [PATCH V5 10/10] PM / OPP: Don't assume platform doesn't have regulators
From: Viresh Kumar @ 2016-11-29 6:36 UTC (permalink / raw)
To: Rafael Wysocki, nm-l0cyMroinI0, sboyd-sgV2jX0FEOL9JmXXK+q4OQ,
Viresh Kumar
Cc: linaro-kernel-cunTk1MwBs8s++Sfvej+rw,
linux-pm-u79uwXL29TY76Z2rM5mHXA,
linux-kernel-u79uwXL29TY76Z2rM5mHXA, Vincent Guittot,
robh-DgEjT+Ai2ygdnm+yROfE0A, d-gerlach-l0cyMroinI0,
broonie-DgEjT+Ai2ygdnm+yROfE0A, devicetree-u79uwXL29TY76Z2rM5mHXA,
Viresh Kumar
In-Reply-To: <cover.1480401041.git.viresh.kumar-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org>
If the regulators aren't set explicitly by the platform, the OPP core
assumes that the platform doesn't have any regulator and uses the
clk-only callback.
If the platform failed to register a regulator with the core, then this
can turn out to be a dangerous assumption as the OPP core will try to
change clk without changing regulators.
Handle that properly by making sure that the DT didn't have any entries
for supply voltages as well.
Signed-off-by: Viresh Kumar <viresh.kumar-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org>
Reviewed-by: Stephen Boyd <sboyd-sgV2jX0FEOL9JmXXK+q4OQ@public.gmane.org>
---
drivers/base/power/opp/core.c | 13 +++++++++++++
1 file changed, 13 insertions(+)
diff --git a/drivers/base/power/opp/core.c b/drivers/base/power/opp/core.c
index 3c9f223709ab..f7a5fb4dbf11 100644
--- a/drivers/base/power/opp/core.c
+++ b/drivers/base/power/opp/core.c
@@ -748,7 +748,20 @@ int dev_pm_opp_set_rate(struct device *dev, unsigned long target_freq)
/* Only frequency scaling */
if (!regulators) {
+ unsigned long u_volt = opp->supplies[0].u_volt;
+
rcu_read_unlock();
+
+ /*
+ * DT contained supply ratings? Consider platform failed to set
+ * regulators.
+ */
+ if (unlikely(u_volt)) {
+ dev_err(dev, "%s: Regulator not registered with OPP core\n",
+ __func__);
+ return -EINVAL;
+ }
+
return _generic_set_opp_clk_only(dev, clk, old_freq, freq);
}
--
2.7.1.410.g6faf27b
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply related
* Re: [PATCH 1/2] PM / Domains: Introduce domain-performance-state binding
From: Viresh Kumar @ 2016-11-29 6:57 UTC (permalink / raw)
To: Stephen Boyd
Cc: Kevin Hilman, Vincent Guittot, Rob Herring, Rafael Wysocki,
linaro-kernel@lists.linaro.org, linux-pm@vger.kernel.org,
linux-kernel, Mark Rutland, Ulf Hansson, Lina Iyer,
devicetree@vger.kernel.org, Nayak Rajendra
In-Reply-To: <4f815e31-22d0-fef7-953c-257fa2bbcb9d@codeaurora.org>
On 28-11-16, 10:27, Stephen Boyd wrote:
> On 11/23/2016 08:40 PM, Viresh Kumar wrote:
> > But even in these cases we wouldn't be using the voltage values within the
> > kernel as we will be giving only a performance state to the M3 core, right?
>
> Nope. In these cases we need to set a certain voltage and we do that by
> requesting it via the M3 core.
Don't we need something like this then ?
parent: power-controller@12340000 {
compatible = "foo,power-controller";
reg = <0x12340000 0x1000>;
#power-domain-cells = <0>;
domain-performance-states = <&perf_state0>;
};
perf_state0: performance_states {
pstate1: pstate@1 {
index = <1>;
/* Optional */
microvolt = <970000 975000 985000>;
};
pstate2: pstate@2 {
index = <2>;
/* Optional */
microvolt = <970000 975000 985000>;
};
pstate3: pstate@3 {
index = <3>;
/* Optional */
microvolt = <970000 975000 985000>;
};
}
cpus {
cpu@0 {
...
power-domain = <&parent>;
operating-points-v2 = <&cpu0_opp_table>;
};
};
cpu0_opp_table: opp_table0 {
compatible = "operating-points-v2";
opp-shared;
opp@1000000000 {
opp-hz = /bits/ 64 <1000000000>;
domain-performance-state = <&pstate1>;
};
opp@1100000000 {
opp-hz = /bits/ 64 <1100000000>;
domain-performance-state = <&pstate2>;
};
opp@1200000000 {
opp-hz = /bits/ 64 <1200000000>;
domain-performance-state = <&pstate3>;
};
};
--
viresh
^ permalink raw reply
* Re: [PATCH] arm64: dts: exynos: Add support for s6e3ha2 panel device for TM2
From: Marek Szyprowski @ 2016-11-29 7:12 UTC (permalink / raw)
To: Hoegeun Kwon, kgene, krzk, devicetree
Cc: linux-samsung-soc, Hyungwon Hwang, Andrzej Hajda, Chanwoo Choi
In-Reply-To: <1480400182-4485-1-git-send-email-hoegeun.kwon@samsung.com>
Hi Hyungwon,
On 2016-11-29 07:16, Hoegeun Kwon wrote:
> From: Hyungwon Hwang <human.hwang@samsung.com>
>
> This patch adds the Panel Device Tree node for s6e3ha2 display
> controller to Exynos5433 SoC dts.
>
> Signed-off-by: Hyungwon Hwang <human.hwang@samsung.com>
> Signed-off-by: Andrzej Hajda <a.hajda@samsung.com>
> Signed-off-by: Chanwoo Choi <cw00.choi@samsung.com>
> Signed-off-by: Hoegeun Kwon <hoegeun.kwon@samsung.com>
> ---
> arch/arm64/boot/dts/exynos/exynos5433-tm2.dts | 35 +++++++++++++++++++++++++++
> 1 file changed, 35 insertions(+)
Please send an updated driver with dt binding description first, then
this patch.
> diff --git a/arch/arm64/boot/dts/exynos/exynos5433-tm2.dts b/arch/arm64/boot/dts/exynos/exynos5433-tm2.dts
> index db879f4..d27f27d 100644
> --- a/arch/arm64/boot/dts/exynos/exynos5433-tm2.dts
> +++ b/arch/arm64/boot/dts/exynos/exynos5433-tm2.dts
> @@ -252,11 +252,46 @@
> reg = <1>;
>
> dsi_out: endpoint {
> + remote-endpoint = <&dsi_in>;
> samsung,burst-clock-frequency = <512000000>;
> samsung,esc-clock-frequency = <16000000>;
> };
> };
> };
> +
> + panel@0 {
> + compatible = "samsung,s6e3ha2";
> + reg = <0>;
> + vdd3-supply = <&ldo27_reg>;
> + vci-supply = <&ldo28_reg>;
> + reset-gpios = <&gpg0 0 0>;
Typically reset gpio is used with GPIO_ACTIVE_LOW flag, so handling this
pin should be changed in the panel driver.
> + panel-en-gpios = <&gpf1 5 0>;
This should be renamed to "enable-gpios", as pointed in
https://patchwork.kernel.org/patch/5714111/
> + te-gpios = <&gpf1 3 1>;
> + power-on-delay= <5>;
> + init-delay = <120>;
> + panel-width-mm = <71>;
> + panel-height-mm = <125>;
> +
> + display-timings {
> + timing-0 {
> + clock-frequency = <14874444>;
> + hactive = <1440>;
> + vactive = <2560>;
> + hfront-porch = <1>;
> + hback-porch = <1>;
> + hsync-len = <1>;
> + vfront-porch = <1>;
> + vback-porch = <15>;
> + vsync-len = <1>;
> + };
> + };
> +
> + port {
> + dsi_in: endpoint {
> + remote-endpoint = <&dsi_out>;
> + };
> + };
> + };
> };
>
> &hsi2c_0 {
Best regards
--
Marek Szyprowski, PhD
Samsung R&D Institute Poland
^ permalink raw reply
* Re: [PATCH 7/10] mmc: sdhci-xenon: Add support to PHYs of Marvell Xenon SDHC
From: Ulf Hansson @ 2016-11-29 7:49 UTC (permalink / raw)
To: Ziji Hu
Cc: Gregory CLEMENT, Adrian Hunter,
linux-mmc-u79uwXL29TY76Z2rM5mHXA@public.gmane.org, Jason Cooper,
Andrew Lunn, Sebastian Hesselbarth, Rob Herring,
devicetree-u79uwXL29TY76Z2rM5mHXA@public.gmane.org,
Thomas Petazzoni,
linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r@public.gmane.org,
Jimmy Xu, Jisheng Zhang, Nadav Haklai, Ryan Gao, Doug Jones,
Victor Gu, Wei(SOCP) Liu, Wilson Ding
In-Reply-To: <c30cead8-17b6-48b0-7355-cd82268842e1-eYqpPyKDWXRBDgjK7y7TUQ@public.gmane.org>
On 29 November 2016 at 03:53, Ziji Hu <huziji-eYqpPyKDWXRBDgjK7y7TUQ@public.gmane.org> wrote:
> Hi Ulf,
>
> On 2016/11/28 23:16, Ulf Hansson wrote:
>> On 28 November 2016 at 12:38, Ziji Hu <huziji-eYqpPyKDWXRBDgjK7y7TUQ@public.gmane.org> wrote:
>>> Hi Ulf,
>>>
>>> On 2016/11/28 19:13, Ulf Hansson wrote:
>>>>>
>>>>> As you suggest, I replace mmc_wait_for_cmd() with mmc_send_tuning(), to
>>>>> send commands for testing current sampling point set in our host PHY.
>>>>>
>>>>> According to my test result, it shows that mmc_send_tuning() can only support
>>>>> tuning command (CMD21/CMD19).
>>>>> As a result, we cannot use mmc_send_tuning() when card is in the speed modes
>>>>> which doesn't support tuning, such as eMMC HS SDR, eMMC HS DRR and
>>>>> SD SDR 12/SDR25/DDR50. Card will not response to tuning commands in those
>>>>> speed modes.
>>>>>
>>>>> Could you please provide suggestions for the speed mode in which tuning is
>>>>> not available?
>>>>>
>>>>
>>>> Normally the mmc host driver shouldn't have to care about what the
>>>> card supports, as that is the responsibility of the mmc core to
>>>> manage.
>>>>
>>>> The host should only need to implement the ->execute_tuning() ops,
>>>> which gets called when the card supports tuning (CMD19/21). Does it
>>>> make sense?
>>>>
>>> I think it is irrelevant to tuning procedure.
>>>
>>> Our host requires to adjust PHY setting after each time ios setting
>>> (SDCLK/bus width/speed mode) is changed.
>>> The simplified sequence is:
>>> mmc change ios --> mmc_set_ios() --> ->set_ios() --> after sdhci_set_ios(),
>>> adjust PHY setting.
>>> During PHY setting adjustment, out host driver has to send commands to
>>> test current sampling point. Tuning is another independent step.
>>
>> For those speed modes (or other ios changes) that *don't* requires
>> tuning, then what will you do when you send the command to confirm the
>> change of PHY setting and it fails?
>>
>> My assumption is that you will fail anyway, by propagating the error
>> to the mmc core. At least that what was my understanding from your
>> earlier replies, right!?
>>
>> Then, I think there are no point having the host driver sending a
>> command to confirm the PHY settings, as the mmc core will anyway
>> discover if something goes wrong when the next command is sent.
>>
>> Please correct me if I am wrong!
>>
>
> Sorry that I didn't make myself clear.
>
> Our host PHY delay line consists of hundreds of sampling points.
> Each sampling point represents a different phase shift.
>
> In lower speed mode, our host driver will scan the delay line.
> It will select and test multiple sampling points, other than testing
> only single sampling point.
>
> If a sampling point fails to transfer cmd/data, our host driver will
> move to test next sampling point, until we find out a group of successful
> sampling points which can transfer cmd/data. At last we will select
> a perfect one from them.
Ahh, I see. Unfortunate, this is going to be very hard to implement properly.
The main problem is that the host driver has *no* knowledge about the
internal state of the card, as that is the responsibility of the mmc
core to keep track of.
If the host driver would send a command during every update of the
"ios" setting, from ->set_ios(), for sure it would lead to commands
being sent that are "forbidden" in the current internal state of the
card.
This would lead to that the card initialization sequence fails,
because the card may move to an unknown internal state and the mmc
core would have no knowledge about what happened.
Hmm..
Can you specify, *exactly*, under which "ios updates" you need to
verify updated PHY setting changes by sending a cmd/data? Also, please
specify if it's enough to only test the CMD line or also DATA lines.
Kind regards
Uffe
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply
* Re: [PATCH v3 1/2] dt-bindings: drm/bridge: adv7511: Add regulator bindings
From: Archit Taneja @ 2016-11-29 8:11 UTC (permalink / raw)
To: Laurent Pinchart; +Cc: linux-arm-msm, robh, dri-devel, devicetree
In-Reply-To: <2390919.s2CzTWN1li@avalon>
On 11/29/2016 12:03 PM, Laurent Pinchart wrote:
> Hi Archit,
>
> Thank you for the patch.
>
> On Tuesday 29 Nov 2016 11:37:41 Archit Taneja wrote:
>> Add the regulator supply properties needed by ADV7511 and ADV7533.
>>
>> The regulators are specified as optional properties since there can
>> be boards which have a fixed supply directly routed to the pins, and
>> these may not be modelled as regulator supplies.
>
> That's why we have support for dummy supplies in the kernel, isn't it ? Isn't
> it better to make the supplies mandatory in the bindings (and obviously
> handling them as optional in the driver for backward-compatibility) ?
I'm a bit unclear on this.
I thought we couldn't add mandatory properties once the device is already
present in DT for one or more platforms.
Say, if we do make it mandatory for future additions, we would need to have
DT property for the supplies for the new platforms. If the regulators on
these boards are fixed supplies, they would be need to be modeled
using "regulator-fixed", possibly without any input supply. Is that
what you're suggesting?
Thanks,
Archit
>
> Apart from that,
>
> Acked-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
>
>> Cc: devicetree@vger.kernel.org
>> Acked-by: Rob Herring <robh@kernel.org>
>> Signed-off-by: Archit Taneja <architt@codeaurora.org>
>> ---
>> v3:
>> - Revert back to having a common avdd-supply property for the 1.8V
>> supplies
>>
>> Documentation/devicetree/bindings/display/bridge/adi,adv7511.txt | 9 ++++++
>> 1 file changed, 9 insertions(+)
>>
>> diff --git
>> a/Documentation/devicetree/bindings/display/bridge/adi,adv7511.txt
>> b/Documentation/devicetree/bindings/display/bridge/adi,adv7511.txt index
>> 6532a59..13d53bc 100644
>> --- a/Documentation/devicetree/bindings/display/bridge/adi,adv7511.txt
>> +++ b/Documentation/devicetree/bindings/display/bridge/adi,adv7511.txt
>> @@ -56,6 +56,15 @@ Optional properties:
>> - adi,disable-timing-generator: Only for ADV7533. Disables the internal
>> timing generator. The chip will rely on the sync signals in the DSI data
>> lanes, rather than generate its own timings for HDMI output.
>> +- avdd-supply: A common 1.8V supply that powers up the AVDD, DVDD and PVDD
>> + pins. On ADV7511, it also feeds to the BGVDD pin. On ADV7533, it also
>> powers
>> + up the A2VDD pin.
>> +- v3p3-supply: A 3.3V supply that powers up the pin called DVDD_3V on
>> + ADV7511 and V3P3 on ADV7533.
>> +
>> +ADV7533 specific supplies:
>> +- v1p2-supply: A supply that powers up the V1P2 pin on the chip. It can be
>> + either 1.2V or 1.8V.
>>
>> Required nodes:
>
--
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum,
a Linux Foundation Collaborative Project
^ permalink raw reply
* Re: [PATCH v2 01/13] devicetree/bindings: display: Document common panel properties
From: Laurent Pinchart @ 2016-11-29 8:27 UTC (permalink / raw)
To: dri-devel
Cc: Rob Herring, linux-renesas-soc, Tomi Valkeinen, Laurent Pinchart,
devicetree
In-Reply-To: <2307840.2mk6E40XHl@avalon>
Hi Rob,
On Tuesday 22 Nov 2016 11:36:55 Laurent Pinchart wrote:
> On Monday 21 Nov 2016 10:48:15 Rob Herring wrote:
> > On Sat, Nov 19, 2016 at 05:28:01AM +0200, Laurent Pinchart wrote:
> >> Document properties common to several display panels in a central
> >> location that can be referenced by the panel device tree bindings.
> >
> > Looks good. Just one comment...
> >
> > [...]
> >
> >> +Connectivity
> >> +------------
> >> +
> >> +- ports: Panels receive video data through one or multiple connections.
> >> While
> >> + the nature of those connections is specific to the panel type, the
> >> + connectivity is expressed in a standard fashion using ports as
> >> specified in
> >> + the device graph bindings defined in
> >> + Documentation/devicetree/bindings/graph.txt.
> >
> > We allow panels to either use graph binding or be a child of the display
> > controller.
>
> I knew that some display controllers use a phandle to the panel (see the
> fsl,panel and nvidia,panel properties), but I didn't know we had panels as
> children of display controller nodes. I don't think we should allow that for
> anything but DSI panels, as the DT hierarchy is based on control buses. Are
> you sure we have other panels instantiated through that mechanism ?
Ping ?
Please note that this file documents properties common to multiple panel DT
bindings, but in no way makes it mandatory to use the OF graph bindings for
panels. The decision is left to individual bindings.
> > Using the graph is preferred, but in the simple cases just a child node is
> > sufficient. This should be described here or somewhere in this doc.
--
Regards,
Laurent Pinchart
^ 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