Devicetree
 help / color / mirror / Atom feed
* Re: [PATCH v3 3/5] devfreq: exynos-bus: convert to use dev_pm_opp_set_rate()
From: Kamil Konieczny @ 2019-07-25 15:15 UTC (permalink / raw)
  To: cwchoi00
  Cc: Chanwoo Choi, Bartlomiej Zolnierkiewicz, Marek Szyprowski,
	Krzysztof Kozlowski, Kukjin Kim, Kyungmin Park, Mark Rutland,
	MyungJoo Ham, Nishanth Menon, Rob Herring, Stephen Boyd,
	Viresh Kumar, devicetree, linux-arm-kernel, linux-kernel,
	Linux PM list, linux-samsung-soc
In-Reply-To: <CAGTfZH1OaYpTheQxWQs7Fs4qcJEGtXQHESLg0CJSsL=dmROpQw@mail.gmail.com>

Hi,

On 25.07.2019 16:53, Chanwoo Choi wrote:
> 2019년 7월 25일 (목) 오후 11:19, Kamil Konieczny
> <k.konieczny@partner.samsung.com>님이 작성:
>>
>> Hi Chanwoo,
>>
>> On 25.07.2019 12:17, Chanwoo Choi wrote:
>>> Hi Kamil,
>>>
>>> Looks good to me. But, I have some comment. Please check them.
>>
>> Thank you for review, please see answers below.
>>
>>> After this patch, exynos_bus_target is perfectly same with
>>> exynos_bus_passive_target. The exynos_bus_passive_target() could be removed.
>>
>> Ok, I will make it in separate patch to simplify review process.
> 
> I think you can just modify this patch without any separate patch.

Do you want me to send v5 with patch 5 squashed in patch 3 ?
 
>>> On 19. 7. 20. 오전 12:05, k.konieczny@partner.samsung.com wrote:
>>>> Reuse opp core code for setting bus clock and voltage. As a side
>>>> effect this allow useage of coupled regulators feature (required
>>>
>>> s/useage/usage ?
>>
>> Good catch, I will change it.
>>
>>>> for boards using Exynos5422/5800 SoCs) because dev_pm_opp_set_rate()
>>>> uses regulator_set_voltage_triplet() for setting regulator voltage
>>>> while the old code used regulator_set_voltage_tol() with fixed
>>>> tolerance. This patch also removes no longer needed parsing of DT
>>>> property "exynos,voltage-tolerance" (no Exynos devfreq DT node uses
>>>> it).
>>>>
>>>> Signed-off-by: Kamil Konieczny <k.konieczny@partner.samsung.com>
>>>> ---
>>>>  drivers/devfreq/exynos-bus.c | 143 +++++++++--------------------------
>>>>  1 file changed, 37 insertions(+), 106 deletions(-)
>>>>
>>>> diff --git a/drivers/devfreq/exynos-bus.c b/drivers/devfreq/exynos-bus.c
>>>> index f391044aa39d..c2147b0912a0 100644
>>>> --- a/drivers/devfreq/exynos-bus.c
>>>> +++ b/drivers/devfreq/exynos-bus.c
>>>> @@ -25,7 +25,6 @@
>>>>  #include <linux/slab.h>
>>>>
>>>>  #define DEFAULT_SATURATION_RATIO    40
>>>> -#define DEFAULT_VOLTAGE_TOLERANCE   2
>>>>
>>>>  struct exynos_bus {
>>>>      struct device *dev;
>>>> @@ -37,9 +36,9 @@ struct exynos_bus {
>>>>
>>>>      unsigned long curr_freq;
>>>>
>>>> -    struct regulator *regulator;
>>>> +    struct opp_table *opp_table;
>>>> +
>>>>      struct clk *clk;
>>>> -    unsigned int voltage_tolerance;
>>>>      unsigned int ratio;
>>>>  };
>>>>
>>>> @@ -99,56 +98,23 @@ static int exynos_bus_target(struct device *dev, unsigned long *freq, u32 flags)
>>>>  {
>>>>      struct exynos_bus *bus = dev_get_drvdata(dev);
>>>>      struct dev_pm_opp *new_opp;
>>>> -    unsigned long old_freq, new_freq, new_volt, tol;
>>>>      int ret = 0;
>>>>
>>>> -    /* Get new opp-bus instance according to new bus clock */
>>>> +    /* Get correct frequency for bus. */
>>>>      new_opp = devfreq_recommended_opp(dev, freq, flags);
>>>>      if (IS_ERR(new_opp)) {
>>>>              dev_err(dev, "failed to get recommended opp instance\n");
>>>>              return PTR_ERR(new_opp);
>>>>      }
>>>>
>>>> -    new_freq = dev_pm_opp_get_freq(new_opp);
>>>> -    new_volt = dev_pm_opp_get_voltage(new_opp);
>>>>      dev_pm_opp_put(new_opp);
>>>>
>>>> -    old_freq = bus->curr_freq;
>>>> -
>>>> -    if (old_freq == new_freq)
>>>> -            return 0;
>>>> -    tol = new_volt * bus->voltage_tolerance / 100;
>>>> -
>>>>      /* Change voltage and frequency according to new OPP level */
>>>>      mutex_lock(&bus->lock);
>>>> +    ret = dev_pm_opp_set_rate(dev, *freq);
>>>> +    if (!ret)
>>>> +            bus->curr_freq = *freq;
>>>>
>>>> -    if (old_freq < new_freq) {
>>>> -            ret = regulator_set_voltage_tol(bus->regulator, new_volt, tol);
>>>> -            if (ret < 0) {
>>>> -                    dev_err(bus->dev, "failed to set voltage\n");
>>>> -                    goto out;
>>>> -            }
>>>> -    }
>>>> -
>>>> -    ret = clk_set_rate(bus->clk, new_freq);
>>>> -    if (ret < 0) {
>>>> -            dev_err(dev, "failed to change clock of bus\n");
>>>> -            clk_set_rate(bus->clk, old_freq);
>>>> -            goto out;
>>>> -    }
>>>> -
>>>> -    if (old_freq > new_freq) {
>>>> -            ret = regulator_set_voltage_tol(bus->regulator, new_volt, tol);
>>>> -            if (ret < 0) {
>>>> -                    dev_err(bus->dev, "failed to set voltage\n");
>>>> -                    goto out;
>>>> -            }
>>>> -    }
>>>> -    bus->curr_freq = new_freq;
>>>> -
>>>> -    dev_dbg(dev, "Set the frequency of bus (%luHz -> %luHz, %luHz)\n",
>>>> -                    old_freq, new_freq, clk_get_rate(bus->clk));
>>>> -out:
>>>>      mutex_unlock(&bus->lock);
>>>>
>>>>      return ret;
>>>> @@ -195,8 +161,8 @@ static void exynos_bus_exit(struct device *dev)
>>>>              dev_warn(dev, "failed to disable the devfreq-event devices\n");
>>>>
>>>>      clk_disable_unprepare(bus->clk);
>>>> -    if (bus->regulator)
>>>> -            regulator_disable(bus->regulator);
>>>> +    if (bus->opp_table)
>>>> +            dev_pm_opp_put_regulators(bus->opp_table);
>>>>
>>>>      dev_pm_opp_of_remove_table(dev);
>>>>  }
>>>> @@ -209,39 +175,23 @@ static int exynos_bus_passive_target(struct device *dev, unsigned long *freq,
>>>>  {
>>>>      struct exynos_bus *bus = dev_get_drvdata(dev);
>>>>      struct dev_pm_opp *new_opp;
>>>> -    unsigned long old_freq, new_freq;
>>>> -    int ret = 0;
>>>> +    int ret;
>>>>
>>>> -    /* Get new opp-bus instance according to new bus clock */
>>>> +    /* Get correct frequency for bus. */
>>>>      new_opp = devfreq_recommended_opp(dev, freq, flags);
>>>>      if (IS_ERR(new_opp)) {
>>>>              dev_err(dev, "failed to get recommended opp instance\n");
>>>>              return PTR_ERR(new_opp);
>>>>      }
>>>>
>>>> -    new_freq = dev_pm_opp_get_freq(new_opp);
>>>>      dev_pm_opp_put(new_opp);
>>>>
>>>> -    old_freq = bus->curr_freq;
>>>> -
>>>> -    if (old_freq == new_freq)
>>>> -            return 0;
>>>> -
>>>>      /* Change the frequency according to new OPP level */
>>>>      mutex_lock(&bus->lock);
>>>> +    ret = dev_pm_opp_set_rate(dev, *freq);
>>>> +    if (!ret)
>>>> +            bus->curr_freq = *freq;
>>>>
>>>> -    ret = clk_set_rate(bus->clk, new_freq);
>>>> -    if (ret < 0) {
>>>> -            dev_err(dev, "failed to set the clock of bus\n");
>>>> -            goto out;
>>>> -    }
>>>> -
>>>> -    *freq = new_freq;
>>>> -    bus->curr_freq = new_freq;
>>>> -
>>>> -    dev_dbg(dev, "Set the frequency of bus (%luHz -> %luHz, %luHz)\n",
>>>> -                    old_freq, new_freq, clk_get_rate(bus->clk));
>>>> -out:
>>>>      mutex_unlock(&bus->lock);
>>>>
>>>>      return ret;
>>>> @@ -259,20 +209,9 @@ static int exynos_bus_parent_parse_of(struct device_node *np,
>>>>                                      struct exynos_bus *bus)
>>>>  {
>>>>      struct device *dev = bus->dev;
>>>> -    int i, ret, count, size;
>>>> -
>>>> -    /* Get the regulator to provide each bus with the power */
>>>> -    bus->regulator = devm_regulator_get(dev, "vdd");
>>>> -    if (IS_ERR(bus->regulator)) {
>>>> -            dev_err(dev, "failed to get VDD regulator\n");
>>>> -            return PTR_ERR(bus->regulator);
>>>> -    }
>>>> -
>>>> -    ret = regulator_enable(bus->regulator);
>>>> -    if (ret < 0) {
>>>> -            dev_err(dev, "failed to enable VDD regulator\n");
>>>> -            return ret;
>>>> -    }
>>>> +    struct opp_table *opp_table;
>>>> +    const char *vdd = "vdd";
>>>> +    int i, count, size;
>>>>
>>>>      /*
>>>>       * Get the devfreq-event devices to get the current utilization of
>>>> @@ -281,26 +220,29 @@ static int exynos_bus_parent_parse_of(struct device_node *np,
>>>>      count = devfreq_event_get_edev_count(dev);
>>>>      if (count < 0) {
>>>>              dev_err(dev, "failed to get the count of devfreq-event dev\n");
>>>> -            ret = count;
>>>> -            goto err_regulator;
>>>> +            return count;
>>>>      }
>>>> -    bus->edev_count = count;
>>>>
>>>> +    bus->edev_count = count;
>>>>      size = sizeof(*bus->edev) * count;
>>>>      bus->edev = devm_kzalloc(dev, size, GFP_KERNEL);
>>>> -    if (!bus->edev) {
>>>> -            ret = -ENOMEM;
>>>> -            goto err_regulator;
>>>> -    }
>>>> +    if (!bus->edev)
>>>> +            return -ENOMEM;
>>>>
>>>>      for (i = 0; i < count; i++) {
>>>>              bus->edev[i] = devfreq_event_get_edev_by_phandle(dev, i);
>>>> -            if (IS_ERR(bus->edev[i])) {
>>>> -                    ret = -EPROBE_DEFER;
>>>> -                    goto err_regulator;
>>>> -            }
>>>> +            if (IS_ERR(bus->edev[i]))
>>>> +                    return -EPROBE_DEFER;
>>>> +    }
>>>> +
>>>> +    opp_table = dev_pm_opp_set_regulators(dev, &vdd, 1);
>>>> +    if (IS_ERR(opp_table)) {
>>>> +            i = PTR_ERR(opp_table);
>>>> +            dev_err(dev, "failed to set regulators %d\n", i);
>>>> +            return i;
>>>
>>> Maybe, you just used the 'i' defined variable instead of adding
>>> new variable. But, I think that you better to add new variable
>>> like 'err' for the readability. Or, jut use the 'PTR_ERR(opp_table)'
>>> directly without any additional variable.
>>
>> I will remove not related changes, so here I will reuse 'ret' variable.
>>
>>>>      }
>>>>
>>>> +    bus->opp_table = opp_table;
>>>
>>> Add blank line.
>>
>> OK
>>
>>>>      /*
>>>>       * Optionally, Get the saturation ratio according to Exynos SoC
>>>>       * When measuring the utilization of each AXI bus with devfreq-event
>>>> @@ -314,16 +256,7 @@ static int exynos_bus_parent_parse_of(struct device_node *np,
>>>>      if (of_property_read_u32(np, "exynos,saturation-ratio", &bus->ratio))
>>>>              bus->ratio = DEFAULT_SATURATION_RATIO;
>>>>
>>>> -    if (of_property_read_u32(np, "exynos,voltage-tolerance",
>>>> -                                    &bus->voltage_tolerance))
>>>> -            bus->voltage_tolerance = DEFAULT_VOLTAGE_TOLERANCE;
>>>> -
>>>>      return 0;
>>>> -
>>>> -err_regulator:
>>>> -    regulator_disable(bus->regulator);
>>>> -
>>>> -    return ret;
>>>>  }
>>>>
>>>>  static int exynos_bus_parse_of(struct exynos_bus *bus)
>>>> @@ -414,12 +347,8 @@ static int exynos_bus_probe(struct platform_device *pdev)
>>>>
>>>>      /* Parse the device-tree to get the resource information */
>>>>      ret = exynos_bus_parse_of(bus);
>>>> -    if (ret < 0) {
>>>> -            if (!passive)
>>>> -                    regulator_disable(bus->regulator);
>>>> -
>>>> -            return ret;
>>>> -    }
>>>> +    if (ret < 0)
>>>> +            goto err_reg;
>>>>
>>>>      if (passive)
>>>>              goto passive;
>>>> @@ -512,10 +441,12 @@ static int exynos_bus_probe(struct platform_device *pdev)
>>>>
>>>>  err:
>>>>      clk_disable_unprepare(bus->clk);
>>>> -    if (!passive)
>>>> -            regulator_disable(bus->regulator);
>>>> -
>>>>      dev_pm_opp_of_remove_table(dev);
>>>
>>> This function removes the 'opp_table'. But, the below code
>>> uses the 'opp_table' variable by dev_pm_opp_put_regulators().
>>>
>>> To disable the regulator, you have to call dev_pm_opp_of_remove_table(dev)
>>> after dev_pm_opp_put_regulators(bus->opp_table).
>>
>> Regulators should be set before dev_pm_opp_add_table(), so exit sequence
>> should be in reverse order,
>>
>> init order:
>>
>> exynos_bus_parent_parse_of()
>>         dev_pm_opp_set_regulators()
>> exynos_bus_parse_of()
>>         clk_prepare_enable()
>>         dev_pm_opp_of_add_table()
>>
>> exit or error order:
>>
>> dev_pm_opp_of_remove_table()
>> clk_disable_unprepare()
>> if (bus->opp_table)
>>         dev_pm_opp_put_regulators(bus->opp_table);
> 
> dev_pm_opp_of_remove_table() have to be called at the end of exit sequence
> after disabling clock and put regulators. Because dev_pm_opp_of_remove_table()
> frees the 'opp_table' pointer of device.
> 
> clk_disable_unprepare()
> if (bus->opp_table)
>           dev_pm_opp_put_regulators(bus->opp_table);
> dev_pm_opp_of_remove_table()

The table is reference counted so it will be freed after count go to zero.

>> I will send v4 soon.
>>
>>>> +err_reg:
>>>> +    if (bus->opp_table) {
>>>> +            dev_pm_opp_put_regulators(bus->opp_table);
>>>> +            bus->opp_table = NULL;
>>>> +    }
>>>>
>>>>      return ret;
>>>>  }

-- 
Best regards,
Kamil Konieczny
Samsung R&D Institute Poland

^ permalink raw reply

* Re: [PATCH v3 6/7] dt-bindings: Add ANX6345 DP/eDP transmitter binding
From: Torsten Duwe @ 2019-07-25 15:17 UTC (permalink / raw)
  To: Vasily Khoruzhick
  Cc: Maxime Ripard, Chen-Yu Tsai, Rob Herring, Mark Rutland,
	Thierry Reding, David Airlie, Daniel Vetter, Andrzej Hajda,
	Laurent Pinchart, Icenowy Zheng, Sean Paul, Harald Geyer,
	Greg Kroah-Hartman, Thomas Gleixner, dri-devel, devicetree,
	arm-linux, linux-kernel
In-Reply-To: <CA+E=qVdu3Hf7ufst-t_CiWkquximGFX8B2RcoQ1x0m++cc8n8Q@mail.gmail.com>

On Mon, Jul 22, 2019 at 11:51:36AM -0700, Vasily Khoruzhick wrote:
> On Mon, Jul 22, 2019 at 8:12 AM Torsten Duwe <duwe@lst.de> wrote:
> >
> > The anx6345 is an ultra-low power DisplayPort/eDP transmitter designed
> > for portable devices.
> >
> > Add a binding document for it.
> 
> I believe you'll have to convert it to yaml format.

Right. Thanks for the reminder.

	Torsten

^ permalink raw reply

* [PATCH v3 6a/7] dt-bindings: Add ANX6345 DP/eDP transmitter binding
From: Torsten Duwe @ 2019-07-25 15:18 UTC (permalink / raw)
  To: Maxime Ripard, Chen-Yu Tsai, Rob Herring, Mark Rutland,
	Thierry Reding, David Airlie, Daniel Vetter, Andrzej Hajda,
	Laurent Pinchart, Icenowy Zheng, Sean Paul, Vasily Khoruzhick,
	Harald Geyer, Greg Kroah-Hartman, Thomas Gleixner
  Cc: dri-devel, devicetree, linux-arm-kernel, linux-kernel
In-Reply-To: <20190722150414.9F97668B20@verein.lst.de>

The anx6345 is an ultra-low power DisplayPort/eDP transmitter designed
for portable devices.

Add a binding document for it.

Signed-off-by: Icenowy Zheng <icenowy@aosc.io>
Signed-off-by: Vasily Khoruzhick <anarsoul@gmail.com>
Reviewed-by: Rob Herring <robh@kernel.org>
Signed-off-by: Torsten Duwe <duwe@suse.de>
Reviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
---
 .../devicetree/bindings/display/bridge/anx6345.yaml |   90 ++++++++++
 1 file changed, 90 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/display/bridge/anx6345.yaml

diff --git a/Documentation/devicetree/bindings/display/bridge/anx6345.yaml b/Documentation/devicetree/bindings/display/bridge/anx6345.yaml
new file mode 100644
index 000000000000..0af092d101c5
--- /dev/null
+++ b/Documentation/devicetree/bindings/display/bridge/anx6345.yaml
@@ -0,0 +1,90 @@
+# SPDX-License-Identifier: GPL-2.0
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/display/bridge/anx6345.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Analogix ANX6345 eDP Transmitter Device Tree Bindings
+
+maintainers:
+  - Torsten Duwe <duwe@lst.de>
+
+description: |
+  The ANX6345 is an ultra-low power Full-HD eDP transmitter designed for
+  portable devices.
+
+properties:
+  compatible:
+    const: analogix,anx6345
+
+  reg:
+    maxItems: 1
+    description: I2C address of the device
+
+  reset-gpios:
+    maxItems: 1
+    description: active low GPIO to use for reset
+
+  dvdd12-supply:
+    maxItems: 1
+    description: Regulator for 1.2V digital core power.
+    $ref: /schemas/types.yaml#/definitions/phandle
+
+  dvdd25-supply:
+    maxItems: 1
+    description: Regulator for 2.5V digital core power.
+    $ref: /schemas/types.yaml#/definitions/phandle
+
+  ports:
+    type: object
+    minItems: 1
+    maxItems: 2
+    description: |
+      Video port 0 for LVTTL input,
+      Video port 1 for eDP output (panel or connector)
+      using the DT bindings defined in
+      Documentation/devicetree/bindings/media/video-interfaces.txt
+
+required:
+  - compatible
+  - reg
+  - reset-gpios
+  - dvdd12-supply
+  - dvdd25-supply
+  - ports
+
+examples:
+ - |
+  anx6345: anx6345@38 {
+      compatible = "analogix,anx6345";
+      reg = <0x38>;
+      reset-gpios = <&pio 3 24 GPIO_ACTIVE_LOW>; /* PD24 */
+      dvdd25-supply = <&reg_dldo2>;
+      dvdd12-supply = <&reg_fldo1>;
+
+      ports {
+          #address-cells = <1>;
+          #size-cells = <0>;
+
+          anx6345_in: port@0 {
+              #address-cells = <1>;
+              #size-cells = <0>;
+              reg = <0>;
+              anx6345_in_tcon0: endpoint@0 {
+                  reg = <0>;
+                  remote-endpoint = <&tcon0_out_anx6345>;
+              };
+          };
+
+          anx6345_out: port@1 {
+              #address-cells = <1>;
+              #size-cells = <0>;
+              reg = <1>;
+
+              anx6345_out_panel: endpoint@0 {
+                  reg = <0>;
+                  remote-endpoint = <&panel_in_edp>;
+              };
+          };
+      };
+  };

^ permalink raw reply related

* [PATCH v2 0/3] Support regulators coupling on NVIDIA Tegra20/30
From: Dmitry Osipenko @ 2019-07-25 15:18 UTC (permalink / raw)
  To: Rob Herring, Thierry Reding, Peter De Schrijver, Jonathan Hunter,
	Mark Brown
  Cc: devicetree, linux-tegra, linux-kernel

Hello,

The voltage regulators need to be coupled on NVIDIA Tegra20 and Tegra30
SoCs in order to provide voltage scaling functionality in a generic way.
All necessary regulator-core patches that added support for the regulators
coupling are already have been merge into mainline kernel. This series
adds customized voltage couplers for Tegra20/30 SoCs, paving the way for
a refined CPUFreq driver that will utilize voltage scaling and other neat
features. This is a resend of a leftover patches from a previous series
[1] that was partially applied by Mark Brown. Please review, thanks in
advance!

[1] https://patchwork.ozlabs.org/project/linux-tegra/list/?series=115626

Changelog:

v2: - Some days ago OPP framework got a change that makes CPU regulator
      to be enabled at the time of CPUFreq's driver initializing OPPs.
      In a result the CPU's voltage is dropped to a minimum value on
      CPUFreq's setting up because there are no consumers at the time
      of regulator's enabling, thus CPU is getting into a big trouble.
      This problem is now resolved in the couplers code by assuming
      that min_uV=current_uV for CPU's regulator if it doesn't have
      any active consumers.

Dmitry Osipenko (3):
  dt-bindings: regulator: Document regulators coupling of NVIDIA
    Tegra20/30 SoCs
  soc/tegra: regulators: Add regulators coupler for Tegra20
  soc/tegra: regulators: Add regulators coupler for Tegra30

 .../nvidia,tegra-regulators-coupling.txt      |  65 ++++
 drivers/soc/tegra/Kconfig                     |  10 +
 drivers/soc/tegra/Makefile                    |   2 +
 drivers/soc/tegra/regulators-tegra20.c        | 364 ++++++++++++++++++
 drivers/soc/tegra/regulators-tegra30.c        | 316 +++++++++++++++
 5 files changed, 757 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/regulator/nvidia,tegra-regulators-coupling.txt
 create mode 100644 drivers/soc/tegra/regulators-tegra20.c
 create mode 100644 drivers/soc/tegra/regulators-tegra30.c

-- 
2.22.0

^ permalink raw reply

* [PATCH v2 1/3] dt-bindings: regulator: Document regulators coupling of NVIDIA Tegra20/30 SoCs
From: Dmitry Osipenko @ 2019-07-25 15:18 UTC (permalink / raw)
  To: Rob Herring, Thierry Reding, Peter De Schrijver, Jonathan Hunter,
	Mark Brown
  Cc: devicetree, linux-tegra, linux-kernel
In-Reply-To: <20190725151832.9802-1-digetx@gmail.com>

There is voltage coupling between three regulators on Tegra20 boards and
between two on Tegra30. The voltage coupling is a SoC-level feature and
thus it is mandatory and common for all of the Tegra boards.

Signed-off-by: Dmitry Osipenko <digetx@gmail.com>
---
 .../nvidia,tegra-regulators-coupling.txt      | 65 +++++++++++++++++++
 1 file changed, 65 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/regulator/nvidia,tegra-regulators-coupling.txt

diff --git a/Documentation/devicetree/bindings/regulator/nvidia,tegra-regulators-coupling.txt b/Documentation/devicetree/bindings/regulator/nvidia,tegra-regulators-coupling.txt
new file mode 100644
index 000000000000..4bf2dbf7c6cc
--- /dev/null
+++ b/Documentation/devicetree/bindings/regulator/nvidia,tegra-regulators-coupling.txt
@@ -0,0 +1,65 @@
+NVIDIA Tegra Regulators Coupling
+================================
+
+NVIDIA Tegra SoC's have a mandatory voltage-coupling between regulators.
+Thus on Tegra20 there are 3 coupled regulators and on NVIDIA Tegra30
+there are 2.
+
+Tegra20 voltage coupling
+------------------------
+
+On Tegra20 SoC's there are 3 coupled regulators: CORE, RTC and CPU.
+The CORE and RTC voltages shall be in a range of 170mV from each other
+and they both shall be higher than the CPU voltage by at least 120mV.
+
+Tegra30 voltage coupling
+------------------------
+
+On Tegra30 SoC's there are 2 coupled regulators: CORE and CPU. The CORE
+and CPU voltages shall be in a range of 300mV from each other and CORE
+voltage shall be higher than the CPU by N mV, where N depends on the CPU
+voltage.
+
+Required properties:
+- nvidia,tegra-core-regulator: Boolean property that designates regulator
+  as the "Core domain" voltage regulator.
+- nvidia,tegra-rtc-regulator: Boolean property that designates regulator
+  as the "RTC domain" voltage regulator.
+- nvidia,tegra-cpu-regulator: Boolean property that designates regulator
+  as the "CPU domain" voltage regulator.
+
+Example:
+
+	pmic {
+		regulators {
+			core_vdd_reg: core {
+				regulator-name = "vdd_core";
+				regulator-min-microvolt = <950000>;
+				regulator-max-microvolt = <1300000>;
+				regulator-coupled-with = <&rtc_vdd_reg &cpu_vdd_reg>;
+				regulator-coupled-max-spread = <170000 550000>;
+
+				nvidia,tegra-core-regulator;
+			};
+
+			rtc_vdd_reg: rtc {
+				regulator-name = "vdd_rtc";
+				regulator-min-microvolt = <950000>;
+				regulator-max-microvolt = <1300000>;
+				regulator-coupled-with = <&core_vdd_reg &cpu_vdd_reg>;
+				regulator-coupled-max-spread = <170000 550000>;
+
+				nvidia,tegra-rtc-regulator;
+			};
+
+			cpu_vdd_reg: cpu {
+				regulator-name = "vdd_cpu";
+				regulator-min-microvolt = <750000>;
+				regulator-max-microvolt = <1125000>;
+				regulator-coupled-with = <&core_vdd_reg &rtc_vdd_reg>;
+				regulator-coupled-max-spread = <550000 550000>;
+
+				nvidia,tegra-cpu-regulator;
+			};
+		};
+	};
-- 
2.22.0

^ permalink raw reply related

* [PATCH v2 2/3] soc/tegra: regulators: Add regulators coupler for Tegra20
From: Dmitry Osipenko @ 2019-07-25 15:18 UTC (permalink / raw)
  To: Rob Herring, Thierry Reding, Peter De Schrijver, Jonathan Hunter,
	Mark Brown
  Cc: devicetree, linux-tegra, linux-kernel
In-Reply-To: <20190725151832.9802-1-digetx@gmail.com>

Add regulators coupler for Tegra20 SoCs that performs voltage balancing
of a coupled regulators and thus provides voltage scaling functionality.

There are 3 coupled regulators on all Tegra20 SoCs: CORE, RTC and CPU.
The CORE and RTC voltages shall be in range of 170mV from each other and
they both shall be higher than the CPU voltage by at least 120mV. This
sounds like it could be handle by a generic voltage balancer, but the CORE
voltage scaling isn't implemented in any of the upstream drivers yet.
It will take quite some time and effort to hook up voltage scaling for
all of the drivers, hence we will use a custom coupler that will manage
the CPU voltage scaling for the starter.

Signed-off-by: Dmitry Osipenko <digetx@gmail.com>
---
 drivers/soc/tegra/Kconfig              |   6 +
 drivers/soc/tegra/Makefile             |   1 +
 drivers/soc/tegra/regulators-tegra20.c | 364 +++++++++++++++++++++++++
 3 files changed, 371 insertions(+)
 create mode 100644 drivers/soc/tegra/regulators-tegra20.c

diff --git a/drivers/soc/tegra/Kconfig b/drivers/soc/tegra/Kconfig
index d98c69efb7e0..7986ab80e07a 100644
--- a/drivers/soc/tegra/Kconfig
+++ b/drivers/soc/tegra/Kconfig
@@ -14,6 +14,7 @@ config ARCH_TEGRA_2x_SOC
 	select PL310_ERRATA_769419 if CACHE_L2X0
 	select SOC_TEGRA_FLOWCTRL
 	select SOC_TEGRA_PMC
+	select SOC_TEGRA20_VOLTAGE_COUPLER
 	select TEGRA_TIMER
 	help
 	  Support for NVIDIA Tegra AP20 and T20 processors, based on the
@@ -134,3 +135,8 @@ config SOC_TEGRA_POWERGATE_BPMP
 	def_bool y
 	depends on PM_GENERIC_DOMAINS
 	depends on TEGRA_BPMP
+
+config SOC_TEGRA20_VOLTAGE_COUPLER
+	bool "Voltage scaling support for Tegra20 SoCs"
+	depends on ARCH_TEGRA_2x_SOC || COMPILE_TEST
+
diff --git a/drivers/soc/tegra/Makefile b/drivers/soc/tegra/Makefile
index 902759fe5f4d..9f0bdd53bef8 100644
--- a/drivers/soc/tegra/Makefile
+++ b/drivers/soc/tegra/Makefile
@@ -5,3 +5,4 @@ obj-y += common.o
 obj-$(CONFIG_SOC_TEGRA_FLOWCTRL) += flowctrl.o
 obj-$(CONFIG_SOC_TEGRA_PMC) += pmc.o
 obj-$(CONFIG_SOC_TEGRA_POWERGATE_BPMP) += powergate-bpmp.o
+obj-$(CONFIG_SOC_TEGRA20_VOLTAGE_COUPLER) += regulators-tegra20.o
diff --git a/drivers/soc/tegra/regulators-tegra20.c b/drivers/soc/tegra/regulators-tegra20.c
new file mode 100644
index 000000000000..84ea3ff316ec
--- /dev/null
+++ b/drivers/soc/tegra/regulators-tegra20.c
@@ -0,0 +1,364 @@
+// SPDX-License-Identifier: GPL-2.0+
+//
+// Voltage regulators coupler for NVIDIA Tegra20
+// Copyright (C) 2019 GRATE-DRIVER project
+//
+// Voltage constraints borrowed from downstream kernel sources
+// Copyright (C) 2010-2011 NVIDIA Corporation
+
+#define pr_fmt(fmt)	"tegra voltage-coupler: " fmt
+
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/of.h>
+#include <linux/regulator/coupler.h>
+#include <linux/regulator/driver.h>
+#include <linux/regulator/machine.h>
+
+struct tegra_regulator_coupler {
+	struct regulator_coupler coupler;
+	struct regulator_dev *core_rdev;
+	struct regulator_dev *cpu_rdev;
+	struct regulator_dev *rtc_rdev;
+	int core_min_uV;
+};
+
+static inline struct tegra_regulator_coupler *
+to_tegra_coupler(struct regulator_coupler *coupler)
+{
+	return container_of(coupler, struct tegra_regulator_coupler, coupler);
+}
+
+static int tegra20_core_limit(struct tegra_regulator_coupler *tegra,
+			      struct regulator_dev *core_rdev)
+{
+	int core_min_uV = 0;
+	int core_max_uV;
+	int core_cur_uV;
+	int err;
+
+	if (tegra->core_min_uV > 0)
+		return tegra->core_min_uV;
+
+	core_cur_uV = regulator_get_voltage_rdev(core_rdev);
+	if (core_cur_uV < 0)
+		return core_cur_uV;
+
+	core_max_uV = max(core_cur_uV, 1200000);
+
+	err = regulator_check_voltage(core_rdev, &core_min_uV, &core_max_uV);
+	if (err)
+		return err;
+
+	/*
+	 * Limit minimum CORE voltage to a value left from bootloader or,
+	 * if it's unreasonably low value, to the most common 1.2v or to
+	 * whatever maximum value defined via board's device-tree.
+	 */
+	tegra->core_min_uV = core_max_uV;
+
+	pr_info("core minimum voltage limited to %duV\n", tegra->core_min_uV);
+
+	return tegra->core_min_uV;
+}
+
+static int tegra20_core_rtc_max_spread(struct regulator_dev *core_rdev,
+				       struct regulator_dev *rtc_rdev)
+{
+	struct coupling_desc *c_desc = &core_rdev->coupling_desc;
+	struct regulator_dev *rdev;
+	int max_spread;
+	unsigned int i;
+
+	for (i = 1; i < c_desc->n_coupled; i++) {
+		max_spread = core_rdev->constraints->max_spread[i - 1];
+		rdev = c_desc->coupled_rdevs[i];
+
+		if (rdev == rtc_rdev && max_spread)
+			return max_spread;
+	}
+
+	pr_err_once("rtc-core max-spread is undefined in device-tree\n");
+
+	return 150000;
+}
+
+static int tegra20_core_rtc_update(struct tegra_regulator_coupler *tegra,
+				   struct regulator_dev *core_rdev,
+				   struct regulator_dev *rtc_rdev,
+				   int cpu_uV, int cpu_min_uV)
+{
+	int core_min_uV, core_max_uV = INT_MAX;
+	int rtc_min_uV, rtc_max_uV = INT_MAX;
+	int core_target_uV;
+	int rtc_target_uV;
+	int max_spread;
+	int core_uV;
+	int rtc_uV;
+	int err;
+
+	/*
+	 * RTC and CORE voltages should be no more than 170mV from each other,
+	 * CPU should be below RTC and CORE by at least 120mV. This applies
+	 * to all Tegra20 SoC's.
+	 */
+	max_spread = tegra20_core_rtc_max_spread(core_rdev, rtc_rdev);
+
+	/*
+	 * The core voltage scaling is currently not hooked up in drivers,
+	 * hence we will limit the minimum core voltage to a reasonable value.
+	 * This should be good enough for the time being.
+	 */
+	core_min_uV = tegra20_core_limit(tegra, core_rdev);
+	if (core_min_uV < 0)
+		return core_min_uV;
+
+	err = regulator_check_voltage(core_rdev, &core_min_uV, &core_max_uV);
+	if (err)
+		return err;
+
+	err = regulator_check_consumers(core_rdev, &core_min_uV, &core_max_uV,
+					PM_SUSPEND_ON);
+	if (err)
+		return err;
+
+	core_uV = regulator_get_voltage_rdev(core_rdev);
+	if (core_uV < 0)
+		return core_uV;
+
+	core_min_uV = max(cpu_min_uV + 125000, core_min_uV);
+	if (core_min_uV > core_max_uV)
+		return -EINVAL;
+
+	if (cpu_uV + 120000 > core_uV)
+		pr_err("core-cpu voltage constraint violated: %d %d\n",
+		       core_uV, cpu_uV + 120000);
+
+	rtc_uV = regulator_get_voltage_rdev(rtc_rdev);
+	if (rtc_uV < 0)
+		return rtc_uV;
+
+	if (cpu_uV + 120000 > rtc_uV)
+		pr_err("rtc-cpu voltage constraint violated: %d %d\n",
+		       rtc_uV, cpu_uV + 120000);
+
+	if (abs(core_uV - rtc_uV) > 170000)
+		pr_err("core-rtc voltage constraint violated: %d %d\n",
+		       core_uV, rtc_uV);
+
+	rtc_min_uV = max(cpu_min_uV + 125000, core_min_uV - max_spread);
+
+	err = regulator_check_voltage(rtc_rdev, &rtc_min_uV, &rtc_max_uV);
+	if (err)
+		return err;
+
+	while (core_uV != core_min_uV || rtc_uV != rtc_min_uV) {
+		if (core_uV < core_min_uV) {
+			core_target_uV = min(core_uV + max_spread, core_min_uV);
+			core_target_uV = min(rtc_uV + max_spread, core_target_uV);
+		} else {
+			core_target_uV = max(core_uV - max_spread, core_min_uV);
+			core_target_uV = max(rtc_uV - max_spread, core_target_uV);
+		}
+
+		err = regulator_set_voltage_rdev(core_rdev,
+						 core_target_uV,
+						 core_max_uV,
+						 PM_SUSPEND_ON);
+		if (err)
+			return err;
+
+		core_uV = core_target_uV;
+
+		if (rtc_uV < rtc_min_uV) {
+			rtc_target_uV = min(rtc_uV + max_spread, rtc_min_uV);
+			rtc_target_uV = min(core_uV + max_spread, rtc_target_uV);
+		} else {
+			rtc_target_uV = max(rtc_uV - max_spread, rtc_min_uV);
+			rtc_target_uV = max(core_uV - max_spread, rtc_target_uV);
+		}
+
+		err = regulator_set_voltage_rdev(rtc_rdev,
+						 rtc_target_uV,
+						 rtc_max_uV,
+						 PM_SUSPEND_ON);
+		if (err)
+			return err;
+
+		rtc_uV = rtc_target_uV;
+	}
+
+	return 0;
+}
+
+static int tegra20_core_voltage_update(struct tegra_regulator_coupler *tegra,
+				       struct regulator_dev *cpu_rdev,
+				       struct regulator_dev *core_rdev,
+				       struct regulator_dev *rtc_rdev)
+{
+	int cpu_uV;
+
+	cpu_uV = regulator_get_voltage_rdev(cpu_rdev);
+	if (cpu_uV < 0)
+		return cpu_uV;
+
+	return tegra20_core_rtc_update(tegra, core_rdev, rtc_rdev,
+				       cpu_uV, cpu_uV);
+}
+
+static int tegra20_cpu_voltage_update(struct tegra_regulator_coupler *tegra,
+				      struct regulator_dev *cpu_rdev,
+				      struct regulator_dev *core_rdev,
+				      struct regulator_dev *rtc_rdev)
+{
+	int cpu_min_uV_consumers = 0;
+	int cpu_max_uV = INT_MAX;
+	int cpu_min_uV = 0;
+	int cpu_uV;
+	int err;
+
+	err = regulator_check_voltage(cpu_rdev, &cpu_min_uV, &cpu_max_uV);
+	if (err)
+		return err;
+
+	err = regulator_check_consumers(cpu_rdev, &cpu_min_uV, &cpu_max_uV,
+					PM_SUSPEND_ON);
+	if (err)
+		return err;
+
+	err = regulator_check_consumers(cpu_rdev, &cpu_min_uV_consumers,
+					&cpu_max_uV, PM_SUSPEND_ON);
+	if (err)
+		return err;
+
+	cpu_uV = regulator_get_voltage_rdev(cpu_rdev);
+	if (cpu_uV < 0)
+		return cpu_uV;
+
+	/*
+	 * CPU's regulator may not have any consumers, hence the voltage
+	 * must not be changed in that case because CPU simply won't
+	 * survive the voltage drop if it's running on a higher frequency.
+	 */
+	if (!cpu_min_uV_consumers)
+		cpu_min_uV = cpu_uV;
+
+	if (cpu_min_uV > cpu_uV) {
+		err = tegra20_core_rtc_update(tegra, core_rdev, rtc_rdev,
+					      cpu_uV, cpu_min_uV);
+		if (err)
+			return err;
+
+		err = regulator_set_voltage_rdev(cpu_rdev, cpu_min_uV,
+						 cpu_max_uV, PM_SUSPEND_ON);
+		if (err)
+			return err;
+	} else if (cpu_min_uV < cpu_uV)  {
+		err = regulator_set_voltage_rdev(cpu_rdev, cpu_min_uV,
+						 cpu_max_uV, PM_SUSPEND_ON);
+		if (err)
+			return err;
+
+		err = tegra20_core_rtc_update(tegra, core_rdev, rtc_rdev,
+					      cpu_uV, cpu_min_uV);
+		if (err)
+			return err;
+	}
+
+	return 0;
+}
+
+static int tegra20_regulator_balance_voltage(struct regulator_coupler *coupler,
+					     struct regulator_dev *rdev,
+					     suspend_state_t state)
+{
+	struct tegra_regulator_coupler *tegra = to_tegra_coupler(coupler);
+	struct regulator_dev *core_rdev = tegra->core_rdev;
+	struct regulator_dev *cpu_rdev = tegra->cpu_rdev;
+	struct regulator_dev *rtc_rdev = tegra->rtc_rdev;
+
+	if ((core_rdev != rdev && cpu_rdev != rdev && rtc_rdev != rdev) ||
+	    state != PM_SUSPEND_ON) {
+		pr_err("regulators are not coupled properly\n");
+		return -EINVAL;
+	}
+
+	if (rdev == cpu_rdev)
+		return tegra20_cpu_voltage_update(tegra, cpu_rdev,
+						  core_rdev, rtc_rdev);
+
+	if (rdev == core_rdev)
+		return tegra20_core_voltage_update(tegra, cpu_rdev,
+						   core_rdev, rtc_rdev);
+
+	pr_err("changing %s voltage not permitted\n", rdev_get_name(rtc_rdev));
+
+	return -EPERM;
+}
+
+static int tegra20_regulator_attach(struct regulator_coupler *coupler,
+				    struct regulator_dev *rdev)
+{
+	struct tegra_regulator_coupler *tegra = to_tegra_coupler(coupler);
+	struct device_node *np = rdev->dev.of_node;
+
+	if (of_property_read_bool(np, "nvidia,tegra-core-regulator") &&
+	    !tegra->core_rdev) {
+		tegra->core_rdev = rdev;
+		return 0;
+	}
+
+	if (of_property_read_bool(np, "nvidia,tegra-rtc-regulator") &&
+	    !tegra->rtc_rdev) {
+		tegra->rtc_rdev = rdev;
+		return 0;
+	}
+
+	if (of_property_read_bool(np, "nvidia,tegra-cpu-regulator") &&
+	    !tegra->cpu_rdev) {
+		tegra->cpu_rdev = rdev;
+		return 0;
+	}
+
+	return -EINVAL;
+}
+
+static int tegra20_regulator_detach(struct regulator_coupler *coupler,
+				    struct regulator_dev *rdev)
+{
+	struct tegra_regulator_coupler *tegra = to_tegra_coupler(coupler);
+
+	if (tegra->core_rdev == rdev) {
+		tegra->core_rdev = NULL;
+		return 0;
+	}
+
+	if (tegra->rtc_rdev == rdev) {
+		tegra->rtc_rdev = NULL;
+		return 0;
+	}
+
+	if (tegra->cpu_rdev == rdev) {
+		tegra->cpu_rdev = NULL;
+		return 0;
+	}
+
+	return -EINVAL;
+}
+
+static struct tegra_regulator_coupler tegra20_coupler = {
+	.coupler = {
+		.attach_regulator = tegra20_regulator_attach,
+		.detach_regulator = tegra20_regulator_detach,
+		.balance_voltage = tegra20_regulator_balance_voltage,
+	},
+};
+
+static int __init tegra_regulator_coupler_init(void)
+{
+	if (!of_machine_is_compatible("nvidia,tegra20"))
+		return 0;
+
+	return regulator_coupler_register(&tegra20_coupler.coupler);
+}
+arch_initcall(tegra_regulator_coupler_init);
-- 
2.22.0

^ permalink raw reply related

* [PATCH v2 3/3] soc/tegra: regulators: Add regulators coupler for Tegra30
From: Dmitry Osipenko @ 2019-07-25 15:18 UTC (permalink / raw)
  To: Rob Herring, Thierry Reding, Peter De Schrijver, Jonathan Hunter,
	Mark Brown
  Cc: devicetree, linux-tegra, linux-kernel
In-Reply-To: <20190725151832.9802-1-digetx@gmail.com>

Add regulators coupler for Tegra30 SoCs that performs voltage balancing
of a coupled regulators and thus provides voltage scaling functionality.

There are 2 coupled regulators on all Tegra30 SoCs: CORE and CPU. The
coupled regulator voltages shall be in a range of 300mV from each other
and CORE voltage shall be higher than the CPU by N mV, where N depends
on the CPU voltage.

Signed-off-by: Dmitry Osipenko <digetx@gmail.com>
---
 drivers/soc/tegra/Kconfig              |   4 +
 drivers/soc/tegra/Makefile             |   1 +
 drivers/soc/tegra/regulators-tegra30.c | 316 +++++++++++++++++++++++++
 3 files changed, 321 insertions(+)
 create mode 100644 drivers/soc/tegra/regulators-tegra30.c

diff --git a/drivers/soc/tegra/Kconfig b/drivers/soc/tegra/Kconfig
index 7986ab80e07a..bc86dc2f4198 100644
--- a/drivers/soc/tegra/Kconfig
+++ b/drivers/soc/tegra/Kconfig
@@ -28,6 +28,7 @@ config ARCH_TEGRA_3x_SOC
 	select PL310_ERRATA_769419 if CACHE_L2X0
 	select SOC_TEGRA_FLOWCTRL
 	select SOC_TEGRA_PMC
+	select SOC_TEGRA30_VOLTAGE_COUPLER
 	select TEGRA_TIMER
 	help
 	  Support for NVIDIA Tegra T30 processor family, based on the
@@ -140,3 +141,6 @@ config SOC_TEGRA20_VOLTAGE_COUPLER
 	bool "Voltage scaling support for Tegra20 SoCs"
 	depends on ARCH_TEGRA_2x_SOC || COMPILE_TEST
 
+config SOC_TEGRA30_VOLTAGE_COUPLER
+	bool "Voltage scaling support for Tegra30 SoCs"
+	depends on ARCH_TEGRA_3x_SOC || COMPILE_TEST
diff --git a/drivers/soc/tegra/Makefile b/drivers/soc/tegra/Makefile
index 9f0bdd53bef8..9c809c1814bd 100644
--- a/drivers/soc/tegra/Makefile
+++ b/drivers/soc/tegra/Makefile
@@ -6,3 +6,4 @@ obj-$(CONFIG_SOC_TEGRA_FLOWCTRL) += flowctrl.o
 obj-$(CONFIG_SOC_TEGRA_PMC) += pmc.o
 obj-$(CONFIG_SOC_TEGRA_POWERGATE_BPMP) += powergate-bpmp.o
 obj-$(CONFIG_SOC_TEGRA20_VOLTAGE_COUPLER) += regulators-tegra20.o
+obj-$(CONFIG_SOC_TEGRA30_VOLTAGE_COUPLER) += regulators-tegra30.o
diff --git a/drivers/soc/tegra/regulators-tegra30.c b/drivers/soc/tegra/regulators-tegra30.c
new file mode 100644
index 000000000000..f19fccfe1a92
--- /dev/null
+++ b/drivers/soc/tegra/regulators-tegra30.c
@@ -0,0 +1,316 @@
+// SPDX-License-Identifier: GPL-2.0+
+//
+// Voltage regulators coupler for NVIDIA Tegra30
+// Copyright (C) 2019 GRATE-DRIVER project
+//
+// Voltage constraints borrowed from downstream kernel sources
+// Copyright (C) 2010-2011 NVIDIA Corporation
+
+#define pr_fmt(fmt)	"tegra voltage-coupler: " fmt
+
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/of.h>
+#include <linux/regulator/coupler.h>
+#include <linux/regulator/driver.h>
+#include <linux/regulator/machine.h>
+
+#include <soc/tegra/fuse.h>
+
+struct tegra_regulator_coupler {
+	struct regulator_coupler coupler;
+	struct regulator_dev *core_rdev;
+	struct regulator_dev *cpu_rdev;
+	int core_min_uV;
+};
+
+static inline struct tegra_regulator_coupler *
+to_tegra_coupler(struct regulator_coupler *coupler)
+{
+	return container_of(coupler, struct tegra_regulator_coupler, coupler);
+}
+
+static int tegra30_core_limit(struct tegra_regulator_coupler *tegra,
+			      struct regulator_dev *core_rdev)
+{
+	int core_min_uV = 0;
+	int core_max_uV;
+	int core_cur_uV;
+	int err;
+
+	if (tegra->core_min_uV > 0)
+		return tegra->core_min_uV;
+
+	core_cur_uV = regulator_get_voltage_rdev(core_rdev);
+	if (core_cur_uV < 0)
+		return core_cur_uV;
+
+	core_max_uV = max(core_cur_uV, 1200000);
+
+	err = regulator_check_voltage(core_rdev, &core_min_uV, &core_max_uV);
+	if (err)
+		return err;
+
+	/*
+	 * Limit minimum CORE voltage to a value left from bootloader or,
+	 * if it's unreasonably low value, to the most common 1.2v or to
+	 * whatever maximum value defined via board's device-tree.
+	 */
+	tegra->core_min_uV = core_max_uV;
+
+	pr_info("core minimum voltage limited to %duV\n", tegra->core_min_uV);
+
+	return tegra->core_min_uV;
+}
+
+static int tegra30_core_cpu_limit(int cpu_uV)
+{
+	if (cpu_uV < 800000)
+		return 950000;
+
+	if (cpu_uV < 900000)
+		return 1000000;
+
+	if (cpu_uV < 1000000)
+		return 1100000;
+
+	if (cpu_uV < 1100000)
+		return 1200000;
+
+	if (cpu_uV < 1250000) {
+		switch (tegra_sku_info.cpu_speedo_id) {
+		case 0 ... 1:
+		case 4:
+		case 7 ... 8:
+			return 1200000;
+
+		default:
+			return 1300000;
+		}
+	}
+
+	return -EINVAL;
+}
+
+static int tegra30_voltage_update(struct tegra_regulator_coupler *tegra,
+				  struct regulator_dev *cpu_rdev,
+				  struct regulator_dev *core_rdev)
+{
+	int core_min_uV, core_max_uV = INT_MAX;
+	int cpu_min_uV, cpu_max_uV = INT_MAX;
+	int cpu_min_uV_consumers = 0;
+	int core_min_limited_uV;
+	int core_target_uV;
+	int cpu_target_uV;
+	int core_max_step;
+	int cpu_max_step;
+	int max_spread;
+	int core_uV;
+	int cpu_uV;
+	int err;
+
+	/*
+	 * CPU voltage should not got lower than 300mV from the CORE.
+	 * CPU voltage should stay below the CORE by 100mV+, depending
+	 * by the CORE voltage. This applies to all Tegra30 SoC's.
+	 */
+	max_spread = cpu_rdev->constraints->max_spread[0];
+	cpu_max_step = cpu_rdev->constraints->max_uV_step;
+	core_max_step = core_rdev->constraints->max_uV_step;
+
+	if (!max_spread) {
+		pr_err_once("cpu-core max-spread is undefined in device-tree\n");
+		max_spread = 300000;
+	}
+
+	if (!cpu_max_step) {
+		pr_err_once("cpu max-step is undefined in device-tree\n");
+		cpu_max_step = 150000;
+	}
+
+	if (!core_max_step) {
+		pr_err_once("core max-step is undefined in device-tree\n");
+		core_max_step = 150000;
+	}
+
+	/*
+	 * The CORE voltage scaling is currently not hooked up in drivers,
+	 * hence we will limit the minimum CORE voltage to a reasonable value.
+	 * This should be good enough for the time being.
+	 */
+	core_min_uV = tegra30_core_limit(tegra, core_rdev);
+	if (core_min_uV < 0)
+		return core_min_uV;
+
+	err = regulator_check_consumers(core_rdev, &core_min_uV, &core_max_uV,
+					PM_SUSPEND_ON);
+	if (err)
+		return err;
+
+	core_uV = regulator_get_voltage_rdev(core_rdev);
+	if (core_uV < 0)
+		return core_uV;
+
+	cpu_min_uV = core_min_uV - max_spread;
+
+	err = regulator_check_consumers(cpu_rdev, &cpu_min_uV, &cpu_max_uV,
+					PM_SUSPEND_ON);
+	if (err)
+		return err;
+
+	err = regulator_check_consumers(cpu_rdev, &cpu_min_uV_consumers,
+					&cpu_max_uV, PM_SUSPEND_ON);
+	if (err)
+		return err;
+
+	err = regulator_check_voltage(cpu_rdev, &cpu_min_uV, &cpu_max_uV);
+	if (err)
+		return err;
+
+	cpu_uV = regulator_get_voltage_rdev(cpu_rdev);
+	if (cpu_uV < 0)
+		return cpu_uV;
+
+	/*
+	 * CPU's regulator may not have any consumers, hence the voltage
+	 * must not be changed in that case because CPU simply won't
+	 * survive the voltage drop if it's running on a higher frequency.
+	 */
+	if (!cpu_min_uV_consumers)
+		cpu_min_uV = cpu_uV;
+
+	/*
+	 * Bootloader shall set up voltages correctly, but if it
+	 * happens that there is a violation, then try to fix it
+	 * at first.
+	 */
+	core_min_limited_uV = tegra30_core_cpu_limit(cpu_uV);
+	if (core_min_limited_uV < 0)
+		return core_min_limited_uV;
+
+	core_min_uV = max(core_min_uV, tegra30_core_cpu_limit(cpu_min_uV));
+
+	err = regulator_check_voltage(core_rdev, &core_min_uV, &core_max_uV);
+	if (err)
+		return err;
+
+	if (core_min_limited_uV > core_uV) {
+		pr_err("core voltage constraint violated: %d %d %d\n",
+		       core_uV, core_min_limited_uV, cpu_uV);
+		goto update_core;
+	}
+
+	while (cpu_uV != cpu_min_uV || core_uV != core_min_uV) {
+		if (cpu_uV < cpu_min_uV) {
+			cpu_target_uV = min(cpu_uV + cpu_max_step, cpu_min_uV);
+		} else {
+			cpu_target_uV = max(cpu_uV - cpu_max_step, cpu_min_uV);
+			cpu_target_uV = max(core_uV - max_spread, cpu_target_uV);
+		}
+
+		err = regulator_set_voltage_rdev(cpu_rdev,
+						 cpu_target_uV,
+						 cpu_max_uV,
+						 PM_SUSPEND_ON);
+		if (err)
+			return err;
+
+		cpu_uV = cpu_target_uV;
+update_core:
+		core_min_limited_uV = tegra30_core_cpu_limit(cpu_uV);
+		if (core_min_limited_uV < 0)
+			return core_min_limited_uV;
+
+		core_target_uV = max(core_min_limited_uV, core_min_uV);
+
+		if (core_uV < core_target_uV) {
+			core_target_uV = min(core_target_uV, core_uV + core_max_step);
+			core_target_uV = min(core_target_uV, cpu_uV + max_spread);
+		} else {
+			core_target_uV = max(core_target_uV, core_uV - core_max_step);
+		}
+
+		err = regulator_set_voltage_rdev(core_rdev,
+						 core_target_uV,
+						 core_max_uV,
+						 PM_SUSPEND_ON);
+		if (err)
+			return err;
+
+		core_uV = core_target_uV;
+	}
+
+	return 0;
+}
+
+static int tegra30_regulator_balance_voltage(struct regulator_coupler *coupler,
+					     struct regulator_dev *rdev,
+					     suspend_state_t state)
+{
+	struct tegra_regulator_coupler *tegra = to_tegra_coupler(coupler);
+	struct regulator_dev *core_rdev = tegra->core_rdev;
+	struct regulator_dev *cpu_rdev = tegra->cpu_rdev;
+
+	if ((core_rdev != rdev && cpu_rdev != rdev) || state != PM_SUSPEND_ON) {
+		pr_err("regulators are not coupled properly\n");
+		return -EINVAL;
+	}
+
+	return tegra30_voltage_update(tegra, cpu_rdev, core_rdev);
+}
+
+static int tegra30_regulator_attach(struct regulator_coupler *coupler,
+				    struct regulator_dev *rdev)
+{
+	struct tegra_regulator_coupler *tegra = to_tegra_coupler(coupler);
+	struct device_node *np = rdev->dev.of_node;
+
+	if (of_property_read_bool(np, "nvidia,tegra-core-regulator") &&
+	    !tegra->core_rdev) {
+		tegra->core_rdev = rdev;
+		return 0;
+	}
+
+	if (of_property_read_bool(np, "nvidia,tegra-cpu-regulator") &&
+	    !tegra->cpu_rdev) {
+		tegra->cpu_rdev = rdev;
+		return 0;
+	}
+
+	return -EINVAL;
+}
+
+static int tegra30_regulator_detach(struct regulator_coupler *coupler,
+				    struct regulator_dev *rdev)
+{
+	struct tegra_regulator_coupler *tegra = to_tegra_coupler(coupler);
+
+	if (tegra->core_rdev == rdev) {
+		tegra->core_rdev = NULL;
+		return 0;
+	}
+
+	if (tegra->cpu_rdev == rdev) {
+		tegra->cpu_rdev = NULL;
+		return 0;
+	}
+
+	return -EINVAL;
+}
+
+static struct tegra_regulator_coupler tegra30_coupler = {
+	.coupler = {
+		.attach_regulator = tegra30_regulator_attach,
+		.detach_regulator = tegra30_regulator_detach,
+		.balance_voltage = tegra30_regulator_balance_voltage,
+	},
+};
+
+static int __init tegra_regulator_coupler_init(void)
+{
+	if (!of_machine_is_compatible("nvidia,tegra30"))
+		return 0;
+
+	return regulator_coupler_register(&tegra30_coupler.coupler);
+}
+arch_initcall(tegra_regulator_coupler_init);
-- 
2.22.0

^ permalink raw reply related

* Re: [PATCH v3 5/7] drm/bridge: Add Analogix anx6345 support
From: Torsten Duwe @ 2019-07-25 15:26 UTC (permalink / raw)
  To: Vasily Khoruzhick, Enric Balletbo i Serra
  Cc: Maxime Ripard, Chen-Yu Tsai, Rob Herring, Mark Rutland,
	Thierry Reding, David Airlie, Daniel Vetter, Andrzej Hajda,
	Laurent Pinchart, Icenowy Zheng, Sean Paul, Harald Geyer,
	Greg Kroah-Hartman, Thomas Gleixner, dri-devel, devicetree,
	arm-linux, linux-kernel
In-Reply-To: <CA+E=qVeSjE1i-ngJWv=GTQDM6HL-VEZWjXH_p_BXy+eP7SvWhg@mail.gmail.com>

On Mon, Jul 22, 2019 at 11:49:48AM -0700, Vasily Khoruzhick wrote:
> On Mon, Jul 22, 2019 at 8:11 AM Torsten Duwe <duwe@lst.de> wrote:
> >
> > +module_i2c_driver(anx6345_driver);
> > +
> > +MODULE_DESCRIPTION("ANX6345 eDP Transmitter driver");
> > +MODULE_AUTHOR("Enric Balletbo i Serra <enric.balletbo@collabora.com>");
> 
> I believe Icenowy is the author of this driver. If you think otherwise
> please add Enric to CC and get his Signed-off-by.

This has already been questioned, and consequently I had a closer look.
Icenowy did the work of finding and splitting the common parts, and copied
and modified those that needed adaption.

Please read the change log(s) in the cover letter(s).

I guess Enric already did sign off his code, which only got moved, copied
and modified.

	Torsten

^ permalink raw reply

* Re: [PATCH v3 5/7] drm/bridge: Add Analogix anx6345 support
From: Enric Balletbo Serra @ 2019-07-25 15:45 UTC (permalink / raw)
  To: Vasily Khoruzhick
  Cc: Torsten Duwe, Mark Rutland, devicetree, Maxime Ripard,
	Greg Kroah-Hartman, linux-kernel, dri-devel, David Airlie,
	Chen-Yu Tsai, Rob Herring, Thierry Reding, Laurent Pinchart,
	Harald Geyer, Sean Paul, Thomas Gleixner, arm-linux,
	Icenowy Zheng
In-Reply-To: <CA+E=qVeSjE1i-ngJWv=GTQDM6HL-VEZWjXH_p_BXy+eP7SvWhg@mail.gmail.com>

Hi,

Missatge de Vasily Khoruzhick <anarsoul@gmail.com> del dia dl., 22 de
jul. 2019 a les 20:50:
>
> On Mon, Jul 22, 2019 at 8:11 AM Torsten Duwe <duwe@lst.de> wrote:
> >
> > From: Icenowy Zheng <icenowy@aosc.io>
> >
> > The ANX6345 is an ultra-low power DisplayPower/eDP transmitter designed
> > for portable devices. This driver adds initial support for RGB to eDP
> > mode, without HPD and interrupts.
> >
> > This is a configuration usually seen in eDP applications.
> >
> > Signed-off-by: Icenowy Zheng <icenowy@aosc.io>
> > Signed-off-by: Vasily Khoruzhick <anarsoul@gmail.com>
> > Signed-off-by: Torsten Duwe <duwe@suse.de>
> > ---
> >  drivers/gpu/drm/bridge/analogix/Kconfig            |  12 +
> >  drivers/gpu/drm/bridge/analogix/Makefile           |   1 +
> >  drivers/gpu/drm/bridge/analogix/analogix-anx6345.c | 797 +++++++++++++++++++++
> >  3 files changed, 810 insertions(+)
> >  create mode 100644 drivers/gpu/drm/bridge/analogix/analogix-anx6345.c
> >
> > --- a/drivers/gpu/drm/bridge/analogix/Kconfig
> > +++ b/drivers/gpu/drm/bridge/analogix/Kconfig
> > @@ -1,6 +1,18 @@
> >  # SPDX-License-Identifier: GPL-2.0-only
> > +config DRM_ANALOGIX_ANX6345
> > +       tristate "Analogix ANX6345 bridge"
> > +       select DRM_ANALOGIX_DP
> > +       select DRM_KMS_HELPER
> > +       select REGMAP_I2C
> > +       help
> > +         ANX6345 is an ultra-low Full-HD DisplayPort/eDP
> > +         transmitter designed for portable devices. The
> > +         ANX6345 transforms the LVTTL RGB output of an
> > +         application processor to eDP or DisplayPort.
> > +
> >  config DRM_ANALOGIX_ANX78XX
> >         tristate "Analogix ANX78XX bridge"
> > +       select DRM_ANALOGIX_DP
> >         select DRM_KMS_HELPER
> >         select REGMAP_I2C
> >         help
> > --- a/drivers/gpu/drm/bridge/analogix/Makefile
> > +++ b/drivers/gpu/drm/bridge/analogix/Makefile
> > @@ -1,4 +1,5 @@
> >  # SPDX-License-Identifier: GPL-2.0-only
> >  analogix_dp-objs := analogix_dp_core.o analogix_dp_reg.o analogix-i2c-dptx.o
> > +obj-$(CONFIG_DRM_ANALOGIX_ANX6345) += analogix-anx6345.o
> >  obj-$(CONFIG_DRM_ANALOGIX_ANX78XX) += analogix-anx78xx.o
> >  obj-$(CONFIG_DRM_ANALOGIX_DP) += analogix_dp.o
> > --- /dev/null
> > +++ b/drivers/gpu/drm/bridge/analogix/analogix-anx6345.c
> > @@ -0,0 +1,793 @@
> > +/* SPDX-License-Identifier: GPL-2.0-only */
> > +/*
> > + * Copyright(c) 2016, Analogix Semiconductor.
> > + * Copyright(c) 2017, Icenowy Zheng <icenowy@aosc.io>
> > + *
> > + * Based on anx7808 driver obtained from chromeos with copyright:
> > + * Copyright(c) 2013, Google Inc.
> > + */
> > +#include <linux/delay.h>
> > +#include <linux/err.h>
> > +#include <linux/gpio/consumer.h>
> > +#include <linux/i2c.h>
> > +#include <linux/interrupt.h>
> > +#include <linux/kernel.h>
> > +#include <linux/module.h>
> > +#include <linux/of_platform.h>
> > +#include <linux/regmap.h>
> > +#include <linux/regulator/consumer.h>
> > +#include <linux/types.h>
> > +
> > +#include <drm/drm_atomic_helper.h>
> > +#include <drm/drm_crtc.h>
> > +#include <drm/drm_crtc_helper.h>
> > +#include <drm/drm_dp_helper.h>
> > +#include <drm/drm_edid.h>
> > +#include <drm/drm_of.h>
> > +#include <drm/drm_panel.h>
> > +#include <drm/drm_print.h>
> > +#include <drm/drm_probe_helper.h>
> > +
> > +#include "analogix-i2c-dptx.h"
> > +#include "analogix-i2c-txcommon.h"
> > +
> > +#define POLL_DELAY             50000 /* us */
> > +#define POLL_TIMEOUT           5000000 /* us */
> > +
> > +#define I2C_IDX_DPTX           0
> > +#define I2C_IDX_TXCOM          1
> > +
> > +static const u8 anx6345_i2c_addresses[] = {
> > +       [I2C_IDX_DPTX]  = ANALOGIX_I2C_DPTX,
> > +       [I2C_IDX_TXCOM] = ANALOGIX_I2C_TXCOMMON,
> > +};
> > +#define I2C_NUM_ADDRESSES      ARRAY_SIZE(anx6345_i2c_addresses)
> > +
> > +struct anx6345 {
> > +       struct drm_dp_aux aux;
> > +       struct drm_bridge bridge;
> > +       struct i2c_client *client;
> > +       struct edid *edid;
> > +       struct drm_connector connector;
> > +       struct drm_dp_link link;
> > +       struct drm_panel *panel;
> > +       struct regulator *dvdd12;
> > +       struct regulator *dvdd25;
> > +       struct gpio_desc *gpiod_reset;
> > +       struct mutex lock;      /* protect EDID access */
> > +
> > +       /* I2C Slave addresses of ANX6345 are mapped as DPTX and SYS */
> > +       struct i2c_client *i2c_clients[I2C_NUM_ADDRESSES];
> > +       struct regmap *map[I2C_NUM_ADDRESSES];
> > +
> > +       u16 chipid;
> > +       u8 dpcd[DP_RECEIVER_CAP_SIZE];
> > +
> > +       bool powered;
> > +};
> > +
> > +static inline struct anx6345 *connector_to_anx6345(struct drm_connector *c)
> > +{
> > +       return container_of(c, struct anx6345, connector);
> > +}
> > +
> > +static inline struct anx6345 *bridge_to_anx6345(struct drm_bridge *bridge)
> > +{
> > +       return container_of(bridge, struct anx6345, bridge);
> > +}
> > +
> > +static int anx6345_set_bits(struct regmap *map, u8 reg, u8 mask)
> > +{
> > +       return regmap_update_bits(map, reg, mask, mask);
> > +}
> > +
> > +static int anx6345_clear_bits(struct regmap *map, u8 reg, u8 mask)
> > +{
> > +       return regmap_update_bits(map, reg, mask, 0);
> > +}
> > +
> > +static ssize_t anx6345_aux_transfer(struct drm_dp_aux *aux,
> > +                                   struct drm_dp_aux_msg *msg)
> > +{
> > +       struct anx6345 *anx6345 = container_of(aux, struct anx6345, aux);
> > +
> > +       return anx_dp_aux_transfer(anx6345->map[I2C_IDX_DPTX], msg);
> > +}
> > +
> > +static int anx6345_dp_link_training(struct anx6345 *anx6345)
> > +{
> > +       unsigned int value;
> > +       u8 dp_bw;
> > +       int err;
> > +
> > +       err = anx6345_clear_bits(anx6345->map[I2C_IDX_TXCOM],
> > +                                SP_POWERDOWN_CTRL_REG,
> > +                                SP_TOTAL_PD);
> > +       if (err)
> > +               return err;
> > +
> > +       err = drm_dp_dpcd_readb(&anx6345->aux, DP_MAX_LINK_RATE, &dp_bw);
> > +       if (err < 0)
> > +               return err;
> > +
> > +       switch (dp_bw) {
> > +       case DP_LINK_BW_1_62:
> > +       case DP_LINK_BW_2_7:
> > +               break;
> > +
> > +       default:
> > +               DRM_DEBUG_KMS("DP bandwidth (%#02x) not supported\n", dp_bw);
> > +               return -EINVAL;
> > +       }
> > +
> > +       err = anx6345_set_bits(anx6345->map[I2C_IDX_TXCOM], SP_VID_CTRL1_REG,
> > +                              SP_VIDEO_MUTE);
> > +       if (err)
> > +               return err;
> > +
> > +       err = anx6345_clear_bits(anx6345->map[I2C_IDX_TXCOM],
> > +                                SP_VID_CTRL1_REG, SP_VIDEO_EN);
> > +       if (err)
> > +               return err;
> > +
> > +       /* Get DPCD info */
> > +       err = drm_dp_dpcd_read(&anx6345->aux, DP_DPCD_REV,
> > +                              &anx6345->dpcd, DP_RECEIVER_CAP_SIZE);
> > +       if (err < 0) {
> > +               DRM_ERROR("Failed to read DPCD: %d\n", err);
> > +               return err;
> > +       }
> > +
> > +       /* Clear channel x SERDES power down */
> > +       err = anx6345_clear_bits(anx6345->map[I2C_IDX_DPTX],
> > +                                SP_DP_ANALOG_POWER_DOWN_REG, SP_CH0_PD);
> > +       if (err)
> > +               return err;
> > +
> > +       /* Check link capabilities */
> > +       err = drm_dp_link_probe(&anx6345->aux, &anx6345->link);
> > +       if (err < 0) {
> > +               DRM_ERROR("Failed to probe link capabilities: %d\n", err);
> > +               return err;
> > +       }
> > +
> > +       /* Power up the sink */
> > +       err = drm_dp_link_power_up(&anx6345->aux, &anx6345->link);
> > +       if (err < 0) {
> > +               DRM_ERROR("Failed to power up DisplayPort link: %d\n", err);
> > +               return err;
> > +       }
> > +
> > +       /* Possibly enable downspread on the sink */
> > +       err = regmap_write(anx6345->map[I2C_IDX_DPTX],
> > +                          SP_DP_DOWNSPREAD_CTRL1_REG, 0);
> > +       if (err)
> > +               return err;
> > +
> > +       if (anx6345->dpcd[DP_MAX_DOWNSPREAD] & DP_MAX_DOWNSPREAD_0_5) {
> > +               DRM_DEBUG("Enable downspread on the sink\n");
> > +               /* 4000PPM */
> > +               err = regmap_write(anx6345->map[I2C_IDX_DPTX],
> > +                                  SP_DP_DOWNSPREAD_CTRL1_REG, 8);
> > +               if (err)
> > +                       return err;
> > +
> > +               err = drm_dp_dpcd_writeb(&anx6345->aux, DP_DOWNSPREAD_CTRL,
> > +                                        DP_SPREAD_AMP_0_5);
> > +               if (err < 0)
> > +                       return err;
> > +       } else {
> > +               err = drm_dp_dpcd_writeb(&anx6345->aux, DP_DOWNSPREAD_CTRL, 0);
> > +               if (err < 0)
> > +                       return err;
> > +       }
> > +
> > +       /* Set the lane count and the link rate on the sink */
> > +       if (drm_dp_enhanced_frame_cap(anx6345->dpcd))
> > +               err = anx6345_set_bits(anx6345->map[I2C_IDX_DPTX],
> > +                                      SP_DP_SYSTEM_CTRL_BASE + 4,
> > +                                      SP_ENHANCED_MODE);
> > +       else
> > +               err = anx6345_clear_bits(anx6345->map[I2C_IDX_DPTX],
> > +                                        SP_DP_SYSTEM_CTRL_BASE + 4,
> > +                                        SP_ENHANCED_MODE);
> > +       if (err)
> > +               return err;
> > +
> > +       value = drm_dp_link_rate_to_bw_code(anx6345->link.rate);
> > +       err = regmap_write(anx6345->map[I2C_IDX_DPTX],
> > +                          SP_DP_MAIN_LINK_BW_SET_REG, value);
> > +       if (err)
> > +               return err;
> > +
> > +       err = regmap_write(anx6345->map[I2C_IDX_DPTX],
> > +                          SP_DP_LANE_COUNT_SET_REG, anx6345->link.num_lanes);
> > +       if (err)
> > +               return err;
> > +
> > +       err = drm_dp_link_configure(&anx6345->aux, &anx6345->link);
> > +       if (err < 0) {
> > +               DRM_ERROR("Failed to configure DisplayPort link: %d\n", err);
> > +               return err;
> > +       }
> > +
> > +       /* Start training on the source */
> > +       err = regmap_write(anx6345->map[I2C_IDX_DPTX], SP_DP_LT_CTRL_REG,
> > +                          SP_LT_EN);
> > +       if (err)
> > +               return err;
> > +
> > +       return regmap_read_poll_timeout(anx6345->map[I2C_IDX_DPTX],
> > +                                      SP_DP_LT_CTRL_REG,
> > +                                      value, !(value & SP_DP_LT_INPROGRESS),
> > +                                      POLL_DELAY, POLL_TIMEOUT);
> > +}
> > +
> > +static int anx6345_tx_initialization(struct anx6345 *anx6345)
> > +{
> > +       int err, i;
> > +
> > +       /* FIXME: colordepth is hardcoded for now */
> > +       err = regmap_write(anx6345->map[I2C_IDX_TXCOM], SP_VID_CTRL2_REG,
> > +                          SP_IN_BPC_6BIT << SP_IN_BPC_SHIFT);
> > +       if (err)
> > +               return err;
> > +
> > +       err = regmap_write(anx6345->map[I2C_IDX_DPTX], SP_DP_PLL_CTRL_REG, 0);
> > +       if (err)
> > +               return err;
> > +
> > +       err = regmap_write(anx6345->map[I2C_IDX_TXCOM],
> > +                          SP_ANALOG_DEBUG1_REG, 0);
> > +       if (err)
> > +               return err;
> > +
> > +       err = regmap_write(anx6345->map[I2C_IDX_DPTX],
> > +                          SP_DP_LINK_DEBUG_CTRL_REG,
> > +                          SP_NEW_PRBS7 | SP_M_VID_DEBUG);
> > +       if (err)
> > +               return err;
> > +
> > +       err = regmap_write(anx6345->map[I2C_IDX_DPTX],
> > +                          SP_DP_ANALOG_POWER_DOWN_REG, 0);
> > +       if (err)
> > +               return err;
> > +
> > +       /* Force HPD */
> > +       err = anx6345_set_bits(anx6345->map[I2C_IDX_DPTX],
> > +                              SP_DP_SYSTEM_CTRL_BASE + 3,
> > +                              SP_HPD_FORCE | SP_HPD_CTRL);
> > +       if (err)
> > +               return err;
> > +
> > +       for (i = 0; i < 4; i++) {
> > +               /* 4 lanes */
> > +               err = regmap_write(anx6345->map[I2C_IDX_DPTX],
> > +                                  SP_DP_LANE0_LT_CTRL_REG + i, 0);
> > +               if (err)
> > +                       return err;
> > +       }
> > +
> > +       /* Reset AUX */
> > +       err = anx6345_set_bits(anx6345->map[I2C_IDX_TXCOM],
> > +                              SP_RESET_CTRL2_REG, SP_AUX_RST);
> > +       if (err)
> > +               return err;
> > +
> > +       return anx6345_clear_bits(anx6345->map[I2C_IDX_TXCOM],
> > +                                SP_RESET_CTRL2_REG, SP_AUX_RST);
> > +}
> > +
> > +static void anx6345_poweron(struct anx6345 *anx6345)
> > +{
> > +       int err;
> > +
> > +       /* Ensure reset is asserted before starting power on sequence */
> > +       gpiod_set_value_cansleep(anx6345->gpiod_reset, 1);
> > +       usleep_range(1000, 2000);
> > +
> > +       err = regulator_enable(anx6345->dvdd12);
> > +       if (err) {
> > +               DRM_ERROR("Failed to enable dvdd12 regulator: %d\n",
> > +                         err);
> > +               return;
> > +       }
> > +
> > +       /* T1 - delay between VDD12 and VDD25 should be 0-2ms */
> > +       usleep_range(1000, 2000);
> > +
> > +       err = regulator_enable(anx6345->dvdd25);
> > +       if (err) {
> > +               DRM_ERROR("Failed to enable dvdd25 regulator: %d\n",
> > +                         err);
> > +               return;
> > +       }
> > +
> > +       /* T2 - delay between RESETN and all power rail stable,
> > +        * should be 2-5ms
> > +        */
> > +       usleep_range(2000, 5000);
> > +
> > +       gpiod_set_value_cansleep(anx6345->gpiod_reset, 0);
> > +
> > +       /* Power on registers module */
> > +       anx6345_set_bits(anx6345->map[I2C_IDX_TXCOM], SP_POWERDOWN_CTRL_REG,
> > +                        SP_HDCP_PD | SP_AUDIO_PD | SP_VIDEO_PD | SP_LINK_PD);
> > +       anx6345_clear_bits(anx6345->map[I2C_IDX_TXCOM], SP_POWERDOWN_CTRL_REG,
> > +                          SP_REGISTER_PD | SP_TOTAL_PD);
> > +
> > +       if (anx6345->panel)
> > +               drm_panel_prepare(anx6345->panel);
> > +
> > +       anx6345->powered = true;
> > +}
> > +
> > +static void anx6345_poweroff(struct anx6345 *anx6345)
> > +{
> > +       int err;
> > +
> > +       gpiod_set_value_cansleep(anx6345->gpiod_reset, 1);
> > +       usleep_range(1000, 2000);
> > +
> > +       if (anx6345->panel)
> > +               drm_panel_unprepare(anx6345->panel);
> > +
> > +       err = regulator_disable(anx6345->dvdd25);
> > +       if (err) {
> > +               DRM_ERROR("Failed to disable dvdd25 regulator: %d\n",
> > +                         err);
> > +               return;
> > +       }
> > +
> > +       usleep_range(5000, 10000);
> > +
> > +       err = regulator_disable(anx6345->dvdd12);
> > +       if (err) {
> > +               DRM_ERROR("Failed to disable dvdd12 regulator: %d\n",
> > +                         err);
> > +               return;
> > +       }
> > +
> > +       usleep_range(1000, 2000);
> > +
> > +       anx6345->powered = false;
> > +}
> > +
> > +static int anx6345_start(struct anx6345 *anx6345)
> > +{
> > +       int err;
> > +
> > +       if (!anx6345->powered)
> > +               anx6345_poweron(anx6345);
> > +
> > +       /* Power on needed modules */
> > +       err = anx6345_clear_bits(anx6345->map[I2C_IDX_TXCOM],
> > +                               SP_POWERDOWN_CTRL_REG,
> > +                               SP_VIDEO_PD | SP_LINK_PD);
> > +
> > +       err = anx6345_tx_initialization(anx6345);
> > +       if (err) {
> > +               DRM_ERROR("Failed eDP transmitter initialization: %d\n", err);
> > +               anx6345_poweroff(anx6345);
> > +               return err;
> > +       }
> > +
> > +       err = anx6345_dp_link_training(anx6345);
> > +       if (err) {
> > +               DRM_ERROR("Failed link training: %d\n", err);
> > +               anx6345_poweroff(anx6345);
> > +               return err;
> > +       }
> > +
> > +       /*
> > +        * This delay seems to help keep the hardware in a good state. Without
> > +        * it, there are times where it fails silently.
> > +        */
> > +       usleep_range(10000, 15000);
> > +
> > +       return 0;
> > +}
> > +
> > +static int anx6345_config_dp_output(struct anx6345 *anx6345)
> > +{
> > +       int err;
> > +
> > +       err = anx6345_clear_bits(anx6345->map[I2C_IDX_TXCOM], SP_VID_CTRL1_REG,
> > +                                SP_VIDEO_MUTE);
> > +       if (err)
> > +               return err;
> > +
> > +       /* Enable DP output */
> > +       err = anx6345_set_bits(anx6345->map[I2C_IDX_TXCOM], SP_VID_CTRL1_REG,
> > +                              SP_VIDEO_EN);
> > +       if (err)
> > +               return err;
> > +
> > +       /* Force stream valid */
> > +       return anx6345_set_bits(anx6345->map[I2C_IDX_DPTX],
> > +                              SP_DP_SYSTEM_CTRL_BASE + 3,
> > +                              SP_STRM_FORCE | SP_STRM_CTRL);
> > +}
> > +
> > +static int anx6345_get_downstream_info(struct anx6345 *anx6345)
> > +{
> > +       u8 value;
> > +       int err;
> > +
> > +       err = drm_dp_dpcd_readb(&anx6345->aux, DP_SINK_COUNT, &value);
> > +       if (err < 0) {
> > +               DRM_ERROR("Get sink count failed %d\n", err);
> > +               return err;
> > +       }
> > +
> > +       if (!DP_GET_SINK_COUNT(value)) {
> > +               DRM_ERROR("Downstream disconnected\n");
> > +               return -EIO;
> > +       }
> > +
> > +       return 0;
> > +}
> > +
> > +static int anx6345_get_modes(struct drm_connector *connector)
> > +{
> > +       struct anx6345 *anx6345 = connector_to_anx6345(connector);
> > +       int err, num_modes = 0;
> > +       bool power_off = false;
> > +
> > +       mutex_lock(&anx6345->lock);
> > +
> > +       if (!anx6345->edid) {
> > +               if (!anx6345->powered) {
> > +                       anx6345_poweron(anx6345);
> > +                       power_off = true;
> > +               }
> > +
> > +               err = anx6345_get_downstream_info(anx6345);
> > +               if (err) {
> > +                       DRM_ERROR("Failed to get downstream info: %d\n", err);
> > +                       goto unlock;
> > +               }
> > +
> > +               anx6345->edid = drm_get_edid(connector, &anx6345->aux.ddc);
> > +               if (!anx6345->edid)
> > +                       DRM_ERROR("Failed to read EDID from panel\n");
> > +
> > +               err = drm_connector_update_edid_property(connector,
> > +                                                        anx6345->edid);
> > +               if (err) {
> > +                       DRM_ERROR("Failed to update EDID property: %d\n", err);
> > +                       goto unlock;
> > +               }
> > +       }
> > +
> > +       num_modes += drm_add_edid_modes(connector, anx6345->edid);
> > +
> > +unlock:
> > +       if (power_off)
> > +               anx6345_poweroff(anx6345);
> > +
> > +       mutex_unlock(&anx6345->lock);
> > +
> > +       if (!num_modes && anx6345->panel)
> > +               num_modes += drm_panel_get_modes(anx6345->panel);
> > +
> > +       return num_modes;
> > +}
> > +
> > +static const struct drm_connector_helper_funcs anx6345_connector_helper_funcs = {
> > +       .get_modes = anx6345_get_modes,
> > +};
> > +
> > +static void
> > +anx6345_connector_destroy(struct drm_connector *connector)
> > +{
> > +       struct anx6345 *anx6345 = connector_to_anx6345(connector);
> > +
> > +       if (anx6345->panel)
> > +               drm_panel_detach(anx6345->panel);
> > +       drm_connector_cleanup(connector);
> > +}
> > +
> > +static const struct drm_connector_funcs anx6345_connector_funcs = {
> > +       .fill_modes = drm_helper_probe_single_connector_modes,
> > +       .destroy = anx6345_connector_destroy,
> > +       .reset = drm_atomic_helper_connector_reset,
> > +       .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
> > +       .atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
> > +};
> > +
> > +static int anx6345_bridge_attach(struct drm_bridge *bridge)
> > +{
> > +       struct anx6345 *anx6345 = bridge_to_anx6345(bridge);
> > +       int err;
> > +
> > +       if (!bridge->encoder) {
> > +               DRM_ERROR("Parent encoder object not found");
> > +               return -ENODEV;
> > +       }
> > +
> > +       /* Register aux channel */
> > +       anx6345->aux.name = "DP-AUX";
> > +       anx6345->aux.dev = &anx6345->client->dev;
> > +       anx6345->aux.transfer = anx6345_aux_transfer;
> > +
> > +       err = drm_dp_aux_register(&anx6345->aux);
> > +       if (err < 0) {
> > +               DRM_ERROR("Failed to register aux channel: %d\n", err);
> > +               return err;
> > +       }
> > +
> > +       err = drm_connector_init(bridge->dev, &anx6345->connector,
> > +                                &anx6345_connector_funcs,
> > +                                DRM_MODE_CONNECTOR_eDP);
> > +       if (err) {
> > +               DRM_ERROR("Failed to initialize connector: %d\n", err);
> > +               return err;
> > +       }
> > +
> > +       drm_connector_helper_add(&anx6345->connector,
> > +                                &anx6345_connector_helper_funcs);
> > +
> > +       err = drm_connector_register(&anx6345->connector);
> > +       if (err) {
> > +               DRM_ERROR("Failed to register connector: %d\n", err);
> > +               return err;
> > +       }
> > +
> > +       anx6345->connector.polled = DRM_CONNECTOR_POLL_HPD;
> > +
> > +       err = drm_connector_attach_encoder(&anx6345->connector,
> > +                                          bridge->encoder);
> > +       if (err) {
> > +               DRM_ERROR("Failed to link up connector to encoder: %d\n", err);
> > +               return err;
> > +       }
> > +
> > +       if (anx6345->panel) {
> > +               err = drm_panel_attach(anx6345->panel, &anx6345->connector);
> > +               if (err) {
> > +                       DRM_ERROR("Failed to attach panel: %d\n", err);
> > +                       return err;
> > +               }
> > +       }
> > +
> > +       return 0;
> > +}
> > +
> > +static enum drm_mode_status
> > +anx6345_bridge_mode_valid(struct drm_bridge *bridge,
> > +                         const struct drm_display_mode *mode)
> > +{
> > +       if (mode->flags & DRM_MODE_FLAG_INTERLACE)
> > +               return MODE_NO_INTERLACE;
> > +
> > +       /* Max 1200p at 5.4 Ghz, one lane */
> > +       if (mode->clock > 154000)
> > +               return MODE_CLOCK_HIGH;
> > +
> > +       return MODE_OK;
> > +}
> > +
> > +static void anx6345_bridge_disable(struct drm_bridge *bridge)
> > +{
> > +       struct anx6345 *anx6345 = bridge_to_anx6345(bridge);
> > +
> > +       /* Power off all modules except configuration registers access */
> > +       anx6345_set_bits(anx6345->map[I2C_IDX_TXCOM], SP_POWERDOWN_CTRL_REG,
> > +                        SP_HDCP_PD | SP_AUDIO_PD | SP_VIDEO_PD | SP_LINK_PD);
> > +       if (anx6345->panel)
> > +               drm_panel_disable(anx6345->panel);
> > +
> > +       if (anx6345->powered)
> > +               anx6345_poweroff(anx6345);
> > +}
> > +
> > +static void anx6345_bridge_enable(struct drm_bridge *bridge)
> > +{
> > +       struct anx6345 *anx6345 = bridge_to_anx6345(bridge);
> > +       int err;
> > +
> > +       if (anx6345->panel)
> > +               drm_panel_enable(anx6345->panel);
> > +
> > +       err = anx6345_start(anx6345);
> > +       if (err) {
> > +               DRM_ERROR("Failed to initialize: %d\n", err);
> > +               return;
> > +       }
> > +
> > +       err = anx6345_config_dp_output(anx6345);
> > +       if (err)
> > +               DRM_ERROR("Failed to enable DP output: %d\n", err);
> > +}
> > +
> > +static const struct drm_bridge_funcs anx6345_bridge_funcs = {
> > +       .attach = anx6345_bridge_attach,
> > +       .mode_valid = anx6345_bridge_mode_valid,
> > +       .disable = anx6345_bridge_disable,
> > +       .enable = anx6345_bridge_enable,
> > +};
> > +
> > +static void unregister_i2c_dummy_clients(struct anx6345 *anx6345)
> > +{
> > +       unsigned int i;
> > +
> > +       for (i = 1; i < ARRAY_SIZE(anx6345->i2c_clients); i++)
> > +               if (anx6345->i2c_clients[i] &&
> > +                   anx6345->i2c_clients[i]->addr != anx6345->client->addr)
> > +                       i2c_unregister_device(anx6345->i2c_clients[i]);
> > +}
> > +
> > +static const struct regmap_config anx6345_regmap_config = {
> > +       .reg_bits = 8,
> > +       .val_bits = 8,
> > +       .max_register = 0xff,
> > +       .cache_type = REGCACHE_NONE,
> > +};
> > +
> > +static const u16 anx6345_chipid_list[] = {
> > +       0x6345,
> > +};
> > +
> > +static bool anx6345_get_chip_id(struct anx6345 *anx6345)
> > +{
> > +       unsigned int i, idl, idh, version;
> > +
> > +       if (regmap_read(anx6345->map[I2C_IDX_TXCOM], SP_DEVICE_IDL_REG, &idl))
> > +               return false;
> > +
> > +       if (regmap_read(anx6345->map[I2C_IDX_TXCOM], SP_DEVICE_IDH_REG, &idh))
> > +               return false;
> > +
> > +       anx6345->chipid = (u8)idl | ((u8)idh << 8);
> > +
> > +       if (regmap_read(anx6345->map[I2C_IDX_TXCOM], SP_DEVICE_VERSION_REG,
> > +                       &version))
> > +               return false;
> > +
> > +       for (i = 0; i < ARRAY_SIZE(anx6345_chipid_list); i++) {
> > +               if (anx6345->chipid == anx6345_chipid_list[i]) {
> > +                       DRM_INFO("Found ANX%x (ver. %d) eDP Transmitter\n",
> > +                                anx6345->chipid, version);
> > +                       return true;
> > +               }
> > +       }
> > +
> > +       DRM_ERROR("ANX%x (ver. %d) not supported by this driver\n",
> > +                 anx6345->chipid, version);
> > +
> > +       return false;
> > +}
> > +
> > +static int anx6345_i2c_probe(struct i2c_client *client,
> > +                            const struct i2c_device_id *id)
> > +{
> > +       struct anx6345 *anx6345;
> > +       struct device *dev;
> > +       int i, err;
> > +
> > +       anx6345 = devm_kzalloc(&client->dev, sizeof(*anx6345), GFP_KERNEL);
> > +       if (!anx6345)
> > +               return -ENOMEM;
> > +
> > +       mutex_init(&anx6345->lock);
> > +
> > +       anx6345->bridge.of_node = client->dev.of_node;
> > +
> > +       anx6345->client = client;
> > +       i2c_set_clientdata(client, anx6345);
> > +
> > +       dev = &anx6345->client->dev;
> > +
> > +       err = drm_of_find_panel_or_bridge(client->dev.of_node, 1, 0,
> > +                                         &anx6345->panel, NULL);
> > +       if (err == -EPROBE_DEFER)
> > +               return err;
> > +
> > +       if (err)
> > +               DRM_DEBUG("No panel found\n");
> > +
> > +       /* 1.2V digital core power regulator  */
> > +       anx6345->dvdd12 = devm_regulator_get(dev, "dvdd12-supply");
> > +       if (IS_ERR(anx6345->dvdd12)) {
> > +               DRM_ERROR("dvdd12-supply not found\n");
> > +               return PTR_ERR(anx6345->dvdd12);
> > +       }
> > +
> > +       /* 2.5V digital core power regulator  */
> > +       anx6345->dvdd25 = devm_regulator_get(dev, "dvdd25-supply");
> > +       if (IS_ERR(anx6345->dvdd25)) {
> > +               DRM_ERROR("dvdd25-supply not found\n");
> > +               return PTR_ERR(anx6345->dvdd25);
> > +       }
> > +
> > +       /* GPIO for chip reset */
> > +       anx6345->gpiod_reset = devm_gpiod_get(dev, "reset", GPIOD_OUT_LOW);
> > +       if (IS_ERR(anx6345->gpiod_reset)) {
> > +               DRM_ERROR("Reset gpio not found\n");
> > +               return PTR_ERR(anx6345->gpiod_reset);
> > +       }
> > +
> > +       /* Map slave addresses of ANX6345 */
> > +       for (i = 0; i < I2C_NUM_ADDRESSES; i++) {
> > +               if (anx6345_i2c_addresses[i] >> 1 != client->addr)
> > +                       anx6345->i2c_clients[i] = i2c_new_dummy(client->adapter,
> > +                                               anx6345_i2c_addresses[i] >> 1);
> > +               else
> > +                       anx6345->i2c_clients[i] = client;
> > +
> > +               if (!anx6345->i2c_clients[i]) {
> > +                       err = -ENOMEM;
> > +                       DRM_ERROR("Failed to reserve I2C bus %02x\n",
> > +                                 anx6345_i2c_addresses[i]);
> > +                       goto err_unregister_i2c;
> > +               }
> > +
> > +               anx6345->map[i] = devm_regmap_init_i2c(anx6345->i2c_clients[i],
> > +                                                      &anx6345_regmap_config);
> > +               if (IS_ERR(anx6345->map[i])) {
> > +                       err = PTR_ERR(anx6345->map[i]);
> > +                       DRM_ERROR("Failed regmap initialization %02x\n",
> > +                                 anx6345_i2c_addresses[i]);
> > +                       goto err_unregister_i2c;
> > +               }
> > +       }
> > +
> > +       /* Look for supported chip ID */
> > +       anx6345_poweron(anx6345);
> > +       if (anx6345_get_chip_id(anx6345)) {
> > +               anx6345->bridge.funcs = &anx6345_bridge_funcs;
> > +               drm_bridge_add(&anx6345->bridge);
> > +
> > +               return 0;
> > +       } else {
> > +               anx6345_poweroff(anx6345);
> > +               err = -ENODEV;
> > +       }
> > +
> > +err_unregister_i2c:
> > +       unregister_i2c_dummy_clients(anx6345);
> > +       return err;
> > +}
> > +
> > +static int anx6345_i2c_remove(struct i2c_client *client)
> > +{
> > +       struct anx6345 *anx6345 = i2c_get_clientdata(client);
> > +
> > +       drm_bridge_remove(&anx6345->bridge);
> > +
> > +       unregister_i2c_dummy_clients(anx6345);
> > +
> > +       kfree(anx6345->edid);
> > +
> > +       mutex_destroy(&anx6345->lock);
> > +
> > +       return 0;
> > +}
> > +
> > +static const struct i2c_device_id anx6345_id[] = {
> > +       { "anx6345", 0 },
> > +       { /* sentinel */ }
> > +};
> > +MODULE_DEVICE_TABLE(i2c, anx6345_id);
> > +
> > +static const struct of_device_id anx6345_match_table[] = {
> > +       { .compatible = "analogix,anx6345", },
> > +       { /* sentinel */ },
> > +};
> > +MODULE_DEVICE_TABLE(of, anx6345_match_table);
> > +
> > +static struct i2c_driver anx6345_driver = {
> > +       .driver = {
> > +                  .name = "anx6345",
> > +                  .of_match_table = of_match_ptr(anx6345_match_table),
> > +                 },
> > +       .probe = anx6345_i2c_probe,
> > +       .remove = anx6345_i2c_remove,
> > +       .id_table = anx6345_id,
> > +};
> > +module_i2c_driver(anx6345_driver);
> > +
> > +MODULE_DESCRIPTION("ANX6345 eDP Transmitter driver");
> > +MODULE_AUTHOR("Enric Balletbo i Serra <enric.balletbo@collabora.com>");
>
> I believe Icenowy is the author of this driver. If you think otherwise
> please add Enric to CC and get his Signed-off-by.
>

I think that the only reason my name appears here is because is a
copy/paste from analogix-anx78xx.c (probably this driver took that
file as a reference?). Indeed I am not the author of this driver, so
Icenowy should be here, not me.

Thanks,
Enric


> > +MODULE_LICENSE("GPL v2");
> _______________________________________________
> dri-devel mailing list
> dri-devel@lists.freedesktop.org
> https://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply

* Re: [PATCH v3 5/7] drm/bridge: Add Analogix anx6345 support
From: Torsten Duwe @ 2019-07-25 15:53 UTC (permalink / raw)
  To: Enric Balletbo Serra
  Cc: Vasily Khoruzhick, Mark Rutland, devicetree, Maxime Ripard,
	Greg Kroah-Hartman, linux-kernel, dri-devel, David Airlie,
	Chen-Yu Tsai, Rob Herring, Thierry Reding, Laurent Pinchart,
	Harald Geyer, Sean Paul, Thomas Gleixner, arm-linux,
	Icenowy Zheng
In-Reply-To: <CAFqH_50s0J_NEevV9b5o-wq-bw+xGaUZ3WyhVDRZKyM2Yn-iVg@mail.gmail.com>

On Thu, Jul 25, 2019 at 05:45:15PM +0200, Enric Balletbo Serra wrote:
> Hi,
> 
> Missatge de Vasily Khoruzhick <anarsoul@gmail.com> del dia dl., 22 de
> jul. 2019 a les 20:50:
> >
> > On Mon, Jul 22, 2019 at 8:11 AM Torsten Duwe <duwe@lst.de> wrote:
> > >
> > > +module_i2c_driver(anx6345_driver);
> > > +
> > > +MODULE_DESCRIPTION("ANX6345 eDP Transmitter driver");
> > > +MODULE_AUTHOR("Enric Balletbo i Serra <enric.balletbo@collabora.com>");
> >
> > I believe Icenowy is the author of this driver. If you think otherwise
> > please add Enric to CC and get his Signed-off-by.
> >
> 
> I think that the only reason my name appears here is because is a
> copy/paste from analogix-anx78xx.c (probably this driver took that

Yes, this is the case.
You wrote / authored 500 lines of it, Icenowy about 300.

> file as a reference?). Indeed I am not the author of this driver, so
> Icenowy should be here, not me.

Very well. Thanks for this clear statement!

	Torsten

^ permalink raw reply

* Re: [PATCH v2 1/2] dt-bindings: arm: imx: add imx8mq nitrogen support
From: Fabio Estevam @ 2019-07-25 15:57 UTC (permalink / raw)
  To: Dafna Hirschfeld
  Cc: Rob Herring, Mark Rutland, Shawn Guo, Sascha Hauer, Sascha Hauer,
	open list:OPEN FIRMWARE AND FLATTENED DEVICE TREE BINDINGS,
	linux-kernel,
	moderated list:ARM/FREESCALE IMX / MXC ARM ARCHITECTURE,
	Ezequiel Garcia, kernel, Gary Bisson, Troy Kisky
In-Reply-To: <20190725121452.16607-2-dafna.hirschfeld@collabora.com>

On Thu, Jul 25, 2019 at 10:56 AM Dafna Hirschfeld
<dafna.hirschfeld@collabora.com> wrote:
>
> From: Gary Bisson <gary.bisson@boundarydevices.com>
>
> i.MX 8Quad is a quad (4x) Cortex-A53 processor with powerful
> graphic and multimedia features.

Instead of describing the SoC, it would be better to describe the
i.MX8M nitrogen board instead.

^ permalink raw reply

* Re: [PATCH v4 3/5] drivers: devfreq: events: extend events by type of counted data
From: Lukasz Luba @ 2019-07-25 16:23 UTC (permalink / raw)
  To: Chanwoo Choi, devicetree, linux-kernel, linux-pm,
	linux-samsung-soc, linux-arm-kernel, myungjoo.ham
  Cc: b.zolnierkie, krzk, robh+dt, mark.rutland, kyungmin.park,
	m.szyprowski, s.nawrocki, kgene, willy.mh.wolff.ml
In-Reply-To: <15375017-2e82-7df8-344c-a9c41d61331c@samsung.com>

Hi Chanwoo,

On 7/24/19 12:24 PM, Chanwoo Choi wrote:
> Hi Lukasz,
> 
> On 19. 7. 24. 오후 7:15, Lukasz Luba wrote:
>> Hi Chanwoo,
>>
>> Could you have a look a this patch, please?
>> This patch has been rewritten accorifing to your suggestion.
>> Krzysztof tried to apply 5/5 DT patch on his current branch,
>> but it is missing earlier stuff.
>> The other patches have needed ACKs so could go through devfreq tree
>> probably, but this one left.
> 
> Sorry for the late reply. It looks good to me.
> 
> Acked-by: Chanwoo Choi <cw00.choi@samsung.com>
Thank you for the ACK.

MyungJoo could you take the patches (apart from 5/5 which will be in
Krzysztof's tree probably) through devfreq tree, please?

Regards,
Lukasz

^ permalink raw reply

* [PATCH v3 0/5] Add veyron tiger and fievel boards
From: Matthias Kaehlcke @ 2019-07-25 16:26 UTC (permalink / raw)
  To: Rob Herring, Mark Rutland, Heiko Stuebner
  Cc: devicetree, linux-arm-kernel, linux-rockchip, linux-kernel,
	Matthias Kaehlcke

This series adds device tree files for the veyron tiger and
fievel boards. It also reorganizes display and backlight
settings for veyron devices, to avoid duplication.

Previous versions of the series didn't have a cover letter,
v2 can be found at
https://patchwork.kernel.org/project/linux-rockchip/list/?series=144987

Matthias Kaehlcke (5):
  ARM: dts: rockchip: move rk3288-veryon display settings into a
    separate file
  ARM: dts: rockchip: consolidate veyron panel and backlight settings
  dt-bindings: ARM: dts: rockchip: Add bindings for
    rk3288-veyron-{fievel,tiger}
  ARM: dts: rockchip: add veyron-fievel board
  ARM: dts: rockchip: add veyron-tiger board

 .../devicetree/bindings/arm/rockchip.yaml     |  30 ++
 arch/arm/boot/dts/Makefile                    |   2 +
 .../boot/dts/rk3288-veyron-chromebook.dtsi    | 115 +------
 arch/arm/boot/dts/rk3288-veyron-edp.dtsi      | 173 ++++++++++
 arch/arm/boot/dts/rk3288-veyron-fievel.dts    | 299 ++++++++++++++++++
 arch/arm/boot/dts/rk3288-veyron-jaq.dts       |  55 ----
 arch/arm/boot/dts/rk3288-veyron-jerry.dts     |  58 ----
 arch/arm/boot/dts/rk3288-veyron-minnie.dts    |  52 ---
 arch/arm/boot/dts/rk3288-veyron-pinky.dts     |  17 +
 arch/arm/boot/dts/rk3288-veyron-speedy.dts    |  58 ----
 arch/arm/boot/dts/rk3288-veyron-tiger.dts     | 125 ++++++++
 11 files changed, 647 insertions(+), 337 deletions(-)
 create mode 100644 arch/arm/boot/dts/rk3288-veyron-edp.dtsi
 create mode 100644 arch/arm/boot/dts/rk3288-veyron-fievel.dts
 create mode 100644 arch/arm/boot/dts/rk3288-veyron-tiger.dts

-- 
2.22.0.709.g102302147b-goog

^ permalink raw reply

* [PATCH v3 1/5] ARM: dts: rockchip: move rk3288-veryon display settings into a separate file
From: Matthias Kaehlcke @ 2019-07-25 16:26 UTC (permalink / raw)
  To: Rob Herring, Mark Rutland, Heiko Stuebner
  Cc: devicetree, linux-arm-kernel, linux-rockchip, linux-kernel,
	Matthias Kaehlcke
In-Reply-To: <20190725162642.250709-1-mka@chromium.org>

The chromebook .dtsi file contains common settings for veyron
Chromebooks with eDP displays. Some veyron devices with a display
aren't Chromebooks (e.g. 'tiger' aka 'AOpen Chromebase Mini'), move
display related bits from the chromebook .dtsi into a separate file
to avoid redundant DT settings.

The new file is included from the chromebook .dtsi and can be
included by non-Chromebook devices with a display.

Signed-off-by: Matthias Kaehlcke <mka@chromium.org>
---
Changes in v3:
- allow MIT license
- move pinctrl section to the bottom

Changes in v2:
- rebased on v5.4-armsoc/dts32 (0d19541e3b45)
---
 .../boot/dts/rk3288-veyron-chromebook.dtsi    | 115 +---------------
 arch/arm/boot/dts/rk3288-veyron-edp.dtsi      | 124 ++++++++++++++++++
 2 files changed, 125 insertions(+), 114 deletions(-)
 create mode 100644 arch/arm/boot/dts/rk3288-veyron-edp.dtsi

diff --git a/arch/arm/boot/dts/rk3288-veyron-chromebook.dtsi b/arch/arm/boot/dts/rk3288-veyron-chromebook.dtsi
index 6a28ce345ba0..ffb60f880b39 100644
--- a/arch/arm/boot/dts/rk3288-veyron-chromebook.dtsi
+++ b/arch/arm/boot/dts/rk3288-veyron-chromebook.dtsi
@@ -10,6 +10,7 @@
 #include <dt-bindings/input/input.h>
 #include "rk3288-veyron.dtsi"
 #include "rk3288-veyron-analog-audio.dtsi"
+#include "rk3288-veyron-edp.dtsi"
 #include "rk3288-veyron-sdmmc.dtsi"
 
 / {
@@ -18,50 +19,6 @@
 		i2c20 = &i2c_tunnel;
 	};
 
-	backlight: backlight {
-		compatible = "pwm-backlight";
-		brightness-levels = <
-			  0   1   2   3   4   5   6   7
-			  8   9  10  11  12  13  14  15
-			 16  17  18  19  20  21  22  23
-			 24  25  26  27  28  29  30  31
-			 32  33  34  35  36  37  38  39
-			 40  41  42  43  44  45  46  47
-			 48  49  50  51  52  53  54  55
-			 56  57  58  59  60  61  62  63
-			 64  65  66  67  68  69  70  71
-			 72  73  74  75  76  77  78  79
-			 80  81  82  83  84  85  86  87
-			 88  89  90  91  92  93  94  95
-			 96  97  98  99 100 101 102 103
-			104 105 106 107 108 109 110 111
-			112 113 114 115 116 117 118 119
-			120 121 122 123 124 125 126 127
-			128 129 130 131 132 133 134 135
-			136 137 138 139 140 141 142 143
-			144 145 146 147 148 149 150 151
-			152 153 154 155 156 157 158 159
-			160 161 162 163 164 165 166 167
-			168 169 170 171 172 173 174 175
-			176 177 178 179 180 181 182 183
-			184 185 186 187 188 189 190 191
-			192 193 194 195 196 197 198 199
-			200 201 202 203 204 205 206 207
-			208 209 210 211 212 213 214 215
-			216 217 218 219 220 221 222 223
-			224 225 226 227 228 229 230 231
-			232 233 234 235 236 237 238 239
-			240 241 242 243 244 245 246 247
-			248 249 250 251 252 253 254 255>;
-		default-brightness-level = <128>;
-		enable-gpios = <&gpio7 RK_PA2 GPIO_ACTIVE_HIGH>;
-		pinctrl-names = "default";
-		pinctrl-0 = <&bl_en>;
-		pwms = <&pwm0 0 1000000 0>;
-		post-pwm-on-delay-ms = <10>;
-		pwm-off-delay-ms = <10>;
-	};
-
 	gpio-charger {
 		compatible = "gpio-charger";
 		charger-type = "mains";
@@ -85,35 +42,6 @@
 		};
 	};
 
-	panel: panel {
-		compatible ="innolux,n116bge", "simple-panel";
-		status = "okay";
-		power-supply = <&vcc33_lcd>;
-		backlight = <&backlight>;
-
-		panel-timing {
-			clock-frequency = <74250000>;
-			hactive = <1366>;
-			hfront-porch = <136>;
-			hback-porch = <60>;
-			hsync-len = <30>;
-			hsync-active = <0>;
-			vactive = <768>;
-			vfront-porch = <8>;
-			vback-porch = <12>;
-			vsync-len = <12>;
-			vsync-active = <0>;
-		};
-
-		ports {
-			panel_in: port {
-				panel_in_edp: endpoint {
-					remote-endpoint = <&edp_out_panel>;
-				};
-			};
-		};
-	};
-
 	/* A non-regulated voltage from power supply or battery */
 	vccsys: vccsys {
 		compatible = "regulator-fixed";
@@ -155,33 +83,6 @@
 	};
 };
 
-&edp {
-	status = "okay";
-
-	pinctrl-names = "default";
-	pinctrl-0 = <&edp_hpd>;
-
-	ports {
-		edp_out: port@1 {
-			reg = <1>;
-			#address-cells = <1>;
-			#size-cells = <0>;
-			edp_out_panel: endpoint@0 {
-				reg = <0>;
-				remote-endpoint = <&panel_in_edp>;
-			};
-		};
-	};
-};
-
-&edp_phy {
-	status = "okay";
-};
-
-&pwm0 {
-	status = "okay";
-};
-
 &rk808 {
 	vcc11-supply = <&vcc_5v>;
 
@@ -234,14 +135,6 @@
 	};
 };
 
-&vopl {
-	status = "okay";
-};
-
-&vopl_mmu {
-	status = "okay";
-};
-
 &pinctrl {
 	pinctrl-0 = <
 		/* Common for sleep and wake, but no owners */
@@ -264,12 +157,6 @@
 		&bt_dev_wake_sleep
 	>;
 
-	backlight {
-		bl_en: bl-en {
-			rockchip,pins = <7 RK_PA2 RK_FUNC_GPIO &pcfg_pull_none>;
-		};
-	};
-
 	buttons {
 		ap_lid_int_l: ap-lid-int-l {
 			rockchip,pins = <0 RK_PA6 RK_FUNC_GPIO &pcfg_pull_up>;
diff --git a/arch/arm/boot/dts/rk3288-veyron-edp.dtsi b/arch/arm/boot/dts/rk3288-veyron-edp.dtsi
new file mode 100644
index 000000000000..c36fb0940478
--- /dev/null
+++ b/arch/arm/boot/dts/rk3288-veyron-edp.dtsi
@@ -0,0 +1,124 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+/*
+ * Google Veyron (and derivatives) fragment for the edp displays
+ *
+ * Copyright 2019 Google LLC
+ */
+
+/ {
+	backlight: backlight {
+		compatible = "pwm-backlight";
+		brightness-levels = <
+			  0   1   2   3   4   5   6   7
+			  8   9  10  11  12  13  14  15
+			 16  17  18  19  20  21  22  23
+			 24  25  26  27  28  29  30  31
+			 32  33  34  35  36  37  38  39
+			 40  41  42  43  44  45  46  47
+			 48  49  50  51  52  53  54  55
+			 56  57  58  59  60  61  62  63
+			 64  65  66  67  68  69  70  71
+			 72  73  74  75  76  77  78  79
+			 80  81  82  83  84  85  86  87
+			 88  89  90  91  92  93  94  95
+			 96  97  98  99 100 101 102 103
+			104 105 106 107 108 109 110 111
+			112 113 114 115 116 117 118 119
+			120 121 122 123 124 125 126 127
+			128 129 130 131 132 133 134 135
+			136 137 138 139 140 141 142 143
+			144 145 146 147 148 149 150 151
+			152 153 154 155 156 157 158 159
+			160 161 162 163 164 165 166 167
+			168 169 170 171 172 173 174 175
+			176 177 178 179 180 181 182 183
+			184 185 186 187 188 189 190 191
+			192 193 194 195 196 197 198 199
+			200 201 202 203 204 205 206 207
+			208 209 210 211 212 213 214 215
+			216 217 218 219 220 221 222 223
+			224 225 226 227 228 229 230 231
+			232 233 234 235 236 237 238 239
+			240 241 242 243 244 245 246 247
+			248 249 250 251 252 253 254 255>;
+		default-brightness-level = <128>;
+		enable-gpios = <&gpio7 RK_PA2 GPIO_ACTIVE_HIGH>;
+		pinctrl-names = "default";
+		pinctrl-0 = <&bl_en>;
+		pwms = <&pwm0 0 1000000 0>;
+		post-pwm-on-delay-ms = <10>;
+		pwm-off-delay-ms = <10>;
+	};
+
+	panel: panel {
+		compatible ="innolux,n116bge", "simple-panel";
+		status = "okay";
+		power-supply = <&vcc33_lcd>;
+		backlight = <&backlight>;
+
+		panel-timing {
+			clock-frequency = <74250000>;
+			hactive = <1366>;
+			hfront-porch = <136>;
+			hback-porch = <60>;
+			hsync-len = <30>;
+			hsync-active = <0>;
+			vactive = <768>;
+			vfront-porch = <8>;
+			vback-porch = <12>;
+			vsync-len = <12>;
+			vsync-active = <0>;
+		};
+
+		ports {
+			panel_in: port {
+				panel_in_edp: endpoint {
+					remote-endpoint = <&edp_out_panel>;
+				};
+			};
+		};
+	};
+};
+
+&edp {
+	status = "okay";
+
+	pinctrl-names = "default";
+	pinctrl-0 = <&edp_hpd>;
+
+	ports {
+		edp_out: port@1 {
+			reg = <1>;
+			#address-cells = <1>;
+			#size-cells = <0>;
+			edp_out_panel: endpoint@0 {
+				reg = <0>;
+				remote-endpoint = <&panel_in_edp>;
+			};
+		};
+	};
+};
+
+&edp_phy {
+	status = "okay";
+};
+
+&pwm0 {
+	status = "okay";
+};
+
+&vopl {
+	status = "okay";
+};
+
+&vopl_mmu {
+	status = "okay";
+};
+
+&pinctrl {
+	backlight {
+		bl_en: bl-en {
+			rockchip,pins = <7 RK_PA2 RK_FUNC_GPIO &pcfg_pull_none>;
+		};
+	};
+};
-- 
2.22.0.709.g102302147b-goog

^ permalink raw reply related

* [PATCH v3 2/5] ARM: dts: rockchip: consolidate veyron panel and backlight settings
From: Matthias Kaehlcke @ 2019-07-25 16:26 UTC (permalink / raw)
  To: Rob Herring, Mark Rutland, Heiko Stuebner
  Cc: devicetree, linux-arm-kernel, linux-rockchip, linux-kernel,
	Matthias Kaehlcke, Douglas Anderson
In-Reply-To: <20190725162642.250709-1-mka@chromium.org>

veyron jaq, jerry, minnie and speedy have mostly redundant regulator
and pinctrl configurations for the panel/backlight. Consolidate these
pieces in the eDP .dtsi.

Also change the default power supply for the panel to
'panel_regulator', instead of overriding it in all the board files.
pinky is the only device that uses 'vcc33_lcd' (the prior default),
so overwrite it in this case. pinky doesn't have a complete display
configuration, to keep things as they were delete the common nodes
that didn't exist previously in pinky's board file.

Reviewed-by: Douglas Anderson <dianders@chromium.org>
Signed-off-by: Matthias Kaehlcke <mka@chromium.org>
---
Changes in v3:
- removed power-supply property from minnie's backlight node
  (it is set in the common part)
- added missing blank in pinky.dts
- added Doug's 'Reviewed-by' tag

Changes in v2:
- rebased on v5.4-armsoc/dts32 (0d19541e3b45)
---
 arch/arm/boot/dts/rk3288-veyron-edp.dtsi   | 51 ++++++++++++++++++-
 arch/arm/boot/dts/rk3288-veyron-jaq.dts    | 55 --------------------
 arch/arm/boot/dts/rk3288-veyron-jerry.dts  | 58 ----------------------
 arch/arm/boot/dts/rk3288-veyron-minnie.dts | 52 -------------------
 arch/arm/boot/dts/rk3288-veyron-pinky.dts  | 17 +++++++
 arch/arm/boot/dts/rk3288-veyron-speedy.dts | 58 ----------------------
 6 files changed, 67 insertions(+), 224 deletions(-)

diff --git a/arch/arm/boot/dts/rk3288-veyron-edp.dtsi b/arch/arm/boot/dts/rk3288-veyron-edp.dtsi
index c36fb0940478..719d936b7822 100644
--- a/arch/arm/boot/dts/rk3288-veyron-edp.dtsi
+++ b/arch/arm/boot/dts/rk3288-veyron-edp.dtsi
@@ -6,6 +6,40 @@
  */
 
 / {
+	backlight_regulator: backlight-regulator {
+		compatible = "regulator-fixed";
+		enable-active-high;
+		gpio = <&gpio2 RK_PB4 GPIO_ACTIVE_HIGH>;
+		pinctrl-names = "default";
+		pinctrl-0 = <&bl_pwr_en>;
+		regulator-name = "backlight_regulator";
+		vin-supply = <&vcc33_sys>;
+		startup-delay-us = <15000>;
+	};
+
+	panel_regulator: panel-regulator {
+		compatible = "regulator-fixed";
+		enable-active-high;
+		gpio = <&gpio7 RK_PB6 GPIO_ACTIVE_HIGH>;
+		pinctrl-names = "default";
+		pinctrl-0 = <&lcd_enable_h>;
+		regulator-name = "panel_regulator";
+		startup-delay-us = <100000>;
+		vin-supply = <&vcc33_sys>;
+	};
+
+	vcc18_lcd: vcc18-lcd {
+		compatible = "regulator-fixed";
+		enable-active-high;
+		gpio = <&gpio2 RK_PB5 GPIO_ACTIVE_HIGH>;
+		pinctrl-names = "default";
+		pinctrl-0 = <&avdd_1v8_disp_en>;
+		regulator-name = "vcc18_lcd";
+		regulator-always-on;
+		regulator-boot-on;
+		vin-supply = <&vcc18_wl>;
+	};
+
 	backlight: backlight {
 		compatible = "pwm-backlight";
 		brightness-levels = <
@@ -48,12 +82,13 @@
 		pwms = <&pwm0 0 1000000 0>;
 		post-pwm-on-delay-ms = <10>;
 		pwm-off-delay-ms = <10>;
+		power-supply = <&backlight_regulator>;
 	};
 
 	panel: panel {
 		compatible ="innolux,n116bge", "simple-panel";
 		status = "okay";
-		power-supply = <&vcc33_lcd>;
+		power-supply = <&panel_regulator>;
 		backlight = <&backlight>;
 
 		panel-timing {
@@ -117,8 +152,22 @@
 
 &pinctrl {
 	backlight {
+		bl_pwr_en: bl_pwr_en {
+			rockchip,pins = <2 RK_PB4 RK_FUNC_GPIO &pcfg_pull_none>;
+		};
+
 		bl_en: bl-en {
 			rockchip,pins = <7 RK_PA2 RK_FUNC_GPIO &pcfg_pull_none>;
 		};
 	};
+
+	lcd {
+		lcd_enable_h: lcd-en {
+			rockchip,pins = <7 RK_PB6 RK_FUNC_GPIO &pcfg_pull_none>;
+		};
+
+		avdd_1v8_disp_en: avdd-1v8-disp-en {
+			rockchip,pins = <2 RK_PB5 RK_FUNC_GPIO &pcfg_pull_none>;
+		};
+	};
 };
diff --git a/arch/arm/boot/dts/rk3288-veyron-jaq.dts b/arch/arm/boot/dts/rk3288-veyron-jaq.dts
index fcd119168cb6..80386203e85b 100644
--- a/arch/arm/boot/dts/rk3288-veyron-jaq.dts
+++ b/arch/arm/boot/dts/rk3288-veyron-jaq.dts
@@ -16,40 +16,6 @@
 		     "google,veyron-jaq-rev3", "google,veyron-jaq-rev2",
 		     "google,veyron-jaq-rev1", "google,veyron-jaq",
 		     "google,veyron", "rockchip,rk3288";
-
-	panel_regulator: panel-regulator {
-		compatible = "regulator-fixed";
-		enable-active-high;
-		gpio = <&gpio7 RK_PB6 GPIO_ACTIVE_HIGH>;
-		pinctrl-names = "default";
-		pinctrl-0 = <&lcd_enable_h>;
-		regulator-name = "panel_regulator";
-		startup-delay-us = <100000>;
-		vin-supply = <&vcc33_sys>;
-	};
-
-	vcc18_lcd: vcc18-lcd {
-		compatible = "regulator-fixed";
-		enable-active-high;
-		gpio = <&gpio2 RK_PB5 GPIO_ACTIVE_HIGH>;
-		pinctrl-names = "default";
-		pinctrl-0 = <&avdd_1v8_disp_en>;
-		regulator-name = "vcc18_lcd";
-		regulator-always-on;
-		regulator-boot-on;
-		vin-supply = <&vcc18_wl>;
-	};
-
-	backlight_regulator: backlight-regulator {
-		compatible = "regulator-fixed";
-		enable-active-high;
-		gpio = <&gpio2 RK_PB4 GPIO_ACTIVE_HIGH>;
-		pinctrl-names = "default";
-		pinctrl-0 = <&bl_pwr_en>;
-		regulator-name = "backlight_regulator";
-		vin-supply = <&vcc33_sys>;
-		startup-delay-us = <15000>;
-	};
 };
 
 &backlight {
@@ -87,11 +53,6 @@
 		232 233 234 235 236 237 238 239
 		240 241 242 243 244 245 246 247
 		248 249 250 251 252 253 254 255>;
-	power-supply = <&backlight_regulator>;
-};
-
-&panel {
-	power-supply = <&panel_regulator>;
 };
 
 &rk808 {
@@ -343,12 +304,6 @@
 };
 
 &pinctrl {
-	backlight {
-		bl_pwr_en: bl_pwr_en {
-			rockchip,pins = <2 RK_PB4 RK_FUNC_GPIO &pcfg_pull_none>;
-		};
-	};
-
 	buck-5v {
 		drv_5v: drv-5v {
 			rockchip,pins = <7 RK_PC5 RK_FUNC_GPIO &pcfg_pull_none>;
@@ -361,16 +316,6 @@
 		};
 	};
 
-	lcd {
-		lcd_enable_h: lcd-en {
-			rockchip,pins = <7 RK_PB6 RK_FUNC_GPIO &pcfg_pull_none>;
-		};
-
-		avdd_1v8_disp_en: avdd-1v8-disp-en {
-			rockchip,pins = <2 RK_PB5 RK_FUNC_GPIO &pcfg_pull_none>;
-		};
-	};
-
 	pmic {
 		dvs_1: dvs-1 {
 			rockchip,pins = <7 RK_PB4 RK_FUNC_GPIO &pcfg_pull_down>;
diff --git a/arch/arm/boot/dts/rk3288-veyron-jerry.dts b/arch/arm/boot/dts/rk3288-veyron-jerry.dts
index 164561f04c1d..a8f55aec09ee 100644
--- a/arch/arm/boot/dts/rk3288-veyron-jerry.dts
+++ b/arch/arm/boot/dts/rk3288-veyron-jerry.dts
@@ -18,48 +18,6 @@
 		     "google,veyron-jerry-rev5", "google,veyron-jerry-rev4",
 		     "google,veyron-jerry-rev3", "google,veyron-jerry",
 		     "google,veyron", "rockchip,rk3288";
-
-	panel_regulator: panel-regulator {
-		compatible = "regulator-fixed";
-		enable-active-high;
-		gpio = <&gpio7 RK_PB6 GPIO_ACTIVE_HIGH>;
-		pinctrl-names = "default";
-		pinctrl-0 = <&lcd_enable_h>;
-		regulator-name = "panel_regulator";
-		startup-delay-us = <100000>;
-		vin-supply = <&vcc33_sys>;
-	};
-
-	vcc18_lcd: vcc18-lcd {
-		compatible = "regulator-fixed";
-		enable-active-high;
-		gpio = <&gpio2 RK_PB5 GPIO_ACTIVE_HIGH>;
-		pinctrl-names = "default";
-		pinctrl-0 = <&avdd_1v8_disp_en>;
-		regulator-name = "vcc18_lcd";
-		regulator-always-on;
-		regulator-boot-on;
-		vin-supply = <&vcc18_wl>;
-	};
-
-	backlight_regulator: backlight-regulator {
-		compatible = "regulator-fixed";
-		enable-active-high;
-		gpio = <&gpio2 RK_PB4 GPIO_ACTIVE_HIGH>;
-		pinctrl-names = "default";
-		pinctrl-0 = <&bl_pwr_en>;
-		regulator-name = "backlight_regulator";
-		vin-supply = <&vcc33_sys>;
-		startup-delay-us = <15000>;
-	};
-};
-
-&backlight {
-	power-supply = <&backlight_regulator>;
-};
-
-&panel {
-	power-supply= <&panel_regulator>;
 };
 
 &rk808 {
@@ -311,12 +269,6 @@
 };
 
 &pinctrl {
-	backlight {
-		bl_pwr_en: bl_pwr_en {
-			rockchip,pins = <2 RK_PB4 RK_FUNC_GPIO &pcfg_pull_none>;
-		};
-	};
-
 	buck-5v {
 		drv_5v: drv-5v {
 			rockchip,pins = <7 RK_PC5 RK_FUNC_GPIO &pcfg_pull_none>;
@@ -329,16 +281,6 @@
 		};
 	};
 
-	lcd {
-		lcd_enable_h: lcd-en {
-			rockchip,pins = <7 RK_PB6 RK_FUNC_GPIO &pcfg_pull_none>;
-		};
-
-		avdd_1v8_disp_en: avdd-1v8-disp-en {
-			rockchip,pins = <2 RK_PB5 RK_FUNC_GPIO &pcfg_pull_none>;
-		};
-	};
-
 	pmic {
 		dvs_1: dvs-1 {
 			rockchip,pins = <7 RK_PB4 RK_FUNC_GPIO &pcfg_pull_down>;
diff --git a/arch/arm/boot/dts/rk3288-veyron-minnie.dts b/arch/arm/boot/dts/rk3288-veyron-minnie.dts
index 4cc7d3659484..55955b082501 100644
--- a/arch/arm/boot/dts/rk3288-veyron-minnie.dts
+++ b/arch/arm/boot/dts/rk3288-veyron-minnie.dts
@@ -15,40 +15,6 @@
 		     "google,veyron-minnie-rev0", "google,veyron-minnie",
 		     "google,veyron", "rockchip,rk3288";
 
-	backlight_regulator: backlight-regulator {
-		compatible = "regulator-fixed";
-		enable-active-high;
-		gpio = <&gpio2 RK_PB4 GPIO_ACTIVE_HIGH>;
-		pinctrl-names = "default";
-		pinctrl-0 = <&bl_pwr_en>;
-		regulator-name = "backlight_regulator";
-		vin-supply = <&vcc33_sys>;
-		startup-delay-us = <15000>;
-	};
-
-	panel_regulator: panel-regulator {
-		compatible = "regulator-fixed";
-		enable-active-high;
-		gpio = <&gpio7 RK_PB6 GPIO_ACTIVE_HIGH>;
-		pinctrl-names = "default";
-		pinctrl-0 = <&lcd_enable_h>;
-		regulator-name = "panel_regulator";
-		startup-delay-us = <100000>;
-		vin-supply = <&vcc33_sys>;
-	};
-
-	vcc18_lcd: vcc18-lcd {
-		compatible = "regulator-fixed";
-		enable-active-high;
-		gpio = <&gpio2 RK_PB5 GPIO_ACTIVE_HIGH>;
-		pinctrl-names = "default";
-		pinctrl-0 = <&avdd_1v8_disp_en>;
-		regulator-name = "vcc18_lcd";
-		regulator-always-on;
-		regulator-boot-on;
-		vin-supply = <&vcc18_wl>;
-	};
-
 	volume_buttons: volume-buttons {
 		compatible = "gpio-keys";
 		pinctrl-names = "default";
@@ -105,7 +71,6 @@
 			232 233 234 235 236 237 238 239
 			240 241 242 243 244 245 246 247
 			248 249 250 251 252 253 254 255>;
-	power-supply = <&backlight_regulator>;
 };
 
 &i2c_tunnel {
@@ -137,7 +102,6 @@
 
 &panel {
 	compatible = "auo,b101ean01", "simple-panel";
-	power-supply= <&panel_regulator>;
 
 	/delete-node/ panel-timing;
 
@@ -411,12 +375,6 @@
 };
 
 &pinctrl {
-	backlight {
-		bl_pwr_en: bl_pwr_en {
-			rockchip,pins = <2 RK_PB4 RK_FUNC_GPIO &pcfg_pull_none>;
-		};
-	};
-
 	buck-5v {
 		drv_5v: drv-5v {
 			rockchip,pins = <7 RK_PC5 RK_FUNC_GPIO &pcfg_pull_none>;
@@ -439,16 +397,6 @@
 		};
 	};
 
-	lcd {
-		lcd_enable_h: lcd-en {
-			rockchip,pins = <7 RK_PB6 RK_FUNC_GPIO &pcfg_pull_none>;
-		};
-
-		avdd_1v8_disp_en: avdd-1v8-disp-en {
-			rockchip,pins = <2 RK_PB5 RK_FUNC_GPIO &pcfg_pull_none>;
-		};
-	};
-
 	pmic {
 		dvs_1: dvs-1 {
 			rockchip,pins = <7 RK_PB4 RK_FUNC_GPIO &pcfg_pull_down>;
diff --git a/arch/arm/boot/dts/rk3288-veyron-pinky.dts b/arch/arm/boot/dts/rk3288-veyron-pinky.dts
index 9b6f4d9b03b6..f420499f300a 100644
--- a/arch/arm/boot/dts/rk3288-veyron-pinky.dts
+++ b/arch/arm/boot/dts/rk3288-veyron-pinky.dts
@@ -14,7 +14,14 @@
 	compatible = "google,veyron-pinky-rev2", "google,veyron-pinky",
 		     "google,veyron", "rockchip,rk3288";
 
+	/delete-node/backlight-regulator;
+	/delete-node/panel-regulator;
 	/delete-node/emmc-pwrseq;
+	/delete-node/vcc18-lcd;
+};
+
+&backlight {
+	/delete-property/power-supply;
 };
 
 &emmc {
@@ -52,7 +59,17 @@
 	i2c-scl-rising-time-ns = <300>;
 };
 
+&panel {
+	power-supply = <&vcc33_lcd>;
+};
+
 &pinctrl {
+	/delete-node/ lcd;
+
+	backlight {
+		/delete-node/ bl_pwr_en;
+	};
+
 	buttons {
 		pwr_key_h: pwr-key-h {
 			rockchip,pins = <0 RK_PA5 RK_FUNC_GPIO &pcfg_pull_none>;
diff --git a/arch/arm/boot/dts/rk3288-veyron-speedy.dts b/arch/arm/boot/dts/rk3288-veyron-speedy.dts
index 9b140db04456..2f2989bc3f9c 100644
--- a/arch/arm/boot/dts/rk3288-veyron-speedy.dts
+++ b/arch/arm/boot/dts/rk3288-veyron-speedy.dts
@@ -16,44 +16,6 @@
 		     "google,veyron-speedy-rev5", "google,veyron-speedy-rev4",
 		     "google,veyron-speedy-rev3", "google,veyron-speedy-rev2",
 		     "google,veyron-speedy", "google,veyron", "rockchip,rk3288";
-
-	panel_regulator: panel-regulator {
-		compatible = "regulator-fixed";
-		enable-active-high;
-		gpio = <&gpio7 RK_PB6 GPIO_ACTIVE_HIGH>;
-		pinctrl-names = "default";
-		pinctrl-0 = <&lcd_enable_h>;
-		regulator-name = "panel_regulator";
-		startup-delay-us = <100000>;
-		vin-supply = <&vcc33_sys>;
-	};
-
-	vcc18_lcd: vcc18-lcd {
-		compatible = "regulator-fixed";
-		enable-active-high;
-		gpio = <&gpio2 RK_PB5 GPIO_ACTIVE_HIGH>;
-		pinctrl-names = "default";
-		pinctrl-0 = <&avdd_1v8_disp_en>;
-		regulator-name = "vcc18_lcd";
-		regulator-always-on;
-		regulator-boot-on;
-		vin-supply = <&vcc18_wl>;
-	};
-
-	backlight_regulator: backlight-regulator {
-		compatible = "regulator-fixed";
-		enable-active-high;
-		gpio = <&gpio2 RK_PB4 GPIO_ACTIVE_HIGH>;
-		pinctrl-names = "default";
-		pinctrl-0 = <&bl_pwr_en>;
-		regulator-name = "backlight_regulator";
-		vin-supply = <&vcc33_sys>;
-		startup-delay-us = <15000>;
-	};
-};
-
-&backlight {
-	power-supply = <&backlight_regulator>;
 };
 
 &cpu_alert0 {
@@ -83,10 +45,6 @@
 	temperature = <90000>;
 };
 
-&panel {
-	power-supply= <&panel_regulator>;
-};
-
 &rk808 {
 	pinctrl-names = "default";
 	pinctrl-0 = <&pmic_int_l>;
@@ -321,12 +279,6 @@
 };
 
 &pinctrl {
-	backlight {
-		bl_pwr_en: bl_pwr_en {
-			rockchip,pins = <2 RK_PB4 RK_FUNC_GPIO &pcfg_pull_none>;
-		};
-	};
-
 	buck-5v {
 		drv_5v: drv-5v {
 			rockchip,pins = <7 RK_PC5 RK_FUNC_GPIO &pcfg_pull_none>;
@@ -339,16 +291,6 @@
 		};
 	};
 
-	lcd {
-		lcd_enable_h: lcd-en {
-			rockchip,pins = <7 RK_PB6 RK_FUNC_GPIO &pcfg_pull_none>;
-		};
-
-		avdd_1v8_disp_en: avdd-1v8-disp-en {
-			rockchip,pins = <2 RK_PB5 RK_FUNC_GPIO &pcfg_pull_none>;
-		};
-	};
-
 	pmic {
 		dvs_1: dvs-1 {
 			rockchip,pins = <7 RK_PB4 RK_FUNC_GPIO &pcfg_pull_down>;
-- 
2.22.0.709.g102302147b-goog

^ permalink raw reply related

* [PATCH v3 3/5] dt-bindings: ARM: dts: rockchip: Add bindings for rk3288-veyron-{fievel,tiger}
From: Matthias Kaehlcke @ 2019-07-25 16:26 UTC (permalink / raw)
  To: Rob Herring, Mark Rutland, Heiko Stuebner
  Cc: devicetree, linux-arm-kernel, linux-rockchip, linux-kernel,
	Matthias Kaehlcke
In-Reply-To: <20190725162642.250709-1-mka@chromium.org>

Fievel is a Chromebox and Tiger a Chromebase with a 10" display and
touchscreen. Tiger and Fievel are based on the same board.

Signed-off-by: Matthias Kaehlcke <mka@chromium.org>
---
Changes in v3:
- patch added to the series
---
 .../devicetree/bindings/arm/rockchip.yaml     | 30 +++++++++++++++++++
 1 file changed, 30 insertions(+)

diff --git a/Documentation/devicetree/bindings/arm/rockchip.yaml b/Documentation/devicetree/bindings/arm/rockchip.yaml
index 34865042f4e4..01eb1e107ea6 100644
--- a/Documentation/devicetree/bindings/arm/rockchip.yaml
+++ b/Documentation/devicetree/bindings/arm/rockchip.yaml
@@ -128,6 +128,21 @@ properties:
           - const: google,veyron
           - const: rockchip,rk3288
 
+      - description: Google Fievel (AOPEN Chromebox Mini)
+        items:
+          - const: google,veyron-fievel-rev8
+          - const: google,veyron-fievel-rev7
+          - const: google,veyron-fievel-rev6
+          - const: google,veyron-fievel-rev5
+          - const: google,veyron-fievel-rev4
+          - const: google,veyron-fievel-rev3
+          - const: google,veyron-fievel-rev2
+          - const: google,veyron-fievel-rev1
+          - const: google,veyron-fievel-rev0
+          - const: google,veyron-fievel
+          - const: google,veyron
+          - const: rockchip,rk3288
+
       - description: Google Gru (dev-board)
         items:
           - const: google,gru-rev15
@@ -311,6 +326,21 @@ properties:
           - const: google,veyron
           - const: rockchip,rk3288
 
+      - description: Google Tiger (AOpen Chromebase Mini)
+        items:
+          - const: google,veyron-tiger-rev8
+          - const: google,veyron-tiger-rev7
+          - const: google,veyron-tiger-rev6
+          - const: google,veyron-tiger-rev5
+          - const: google,veyron-tiger-rev4
+          - const: google,veyron-tiger-rev3
+          - const: google,veyron-tiger-rev2
+          - const: google,veyron-tiger-rev1
+          - const: google,veyron-tiger-rev0
+          - const: google,veyron-tiger
+          - const: google,veyron
+          - const: rockchip,rk3288
+
       - description: Haoyu MarsBoard RK3066
         items:
           - const: haoyu,marsboard-rk3066
-- 
2.22.0.709.g102302147b-goog

^ permalink raw reply related

* [PATCH v3 4/5] ARM: dts: rockchip: add veyron-fievel board
From: Matthias Kaehlcke @ 2019-07-25 16:26 UTC (permalink / raw)
  To: Rob Herring, Mark Rutland, Heiko Stuebner
  Cc: devicetree, linux-arm-kernel, linux-rockchip, linux-kernel,
	Matthias Kaehlcke
In-Reply-To: <20190725162642.250709-1-mka@chromium.org>

Also known as AOpen Chromebox Mini.

Signed-off-by: Matthias Kaehlcke <mka@chromium.org>
---
Changes in v3:
- patch added to the series
---
 arch/arm/boot/dts/Makefile                 |   1 +
 arch/arm/boot/dts/rk3288-veyron-fievel.dts | 299 +++++++++++++++++++++
 2 files changed, 300 insertions(+)
 create mode 100644 arch/arm/boot/dts/rk3288-veyron-fievel.dts

diff --git a/arch/arm/boot/dts/Makefile b/arch/arm/boot/dts/Makefile
index 9159fa2cea90..9fd1e075c624 100644
--- a/arch/arm/boot/dts/Makefile
+++ b/arch/arm/boot/dts/Makefile
@@ -919,6 +919,7 @@ dtb-$(CONFIG_ARCH_ROCKCHIP) += \
 	rk3288-tinker.dtb \
 	rk3288-tinker-s.dtb \
 	rk3288-veyron-brain.dtb \
+	rk3288-veyron-fievel.dtb \
 	rk3288-veyron-jaq.dtb \
 	rk3288-veyron-jerry.dtb \
 	rk3288-veyron-mickey.dtb \
diff --git a/arch/arm/boot/dts/rk3288-veyron-fievel.dts b/arch/arm/boot/dts/rk3288-veyron-fievel.dts
new file mode 100644
index 000000000000..a9716fc3f50a
--- /dev/null
+++ b/arch/arm/boot/dts/rk3288-veyron-fievel.dts
@@ -0,0 +1,299 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+/*
+ * Google Veyron Fievel Rev 0+ board device tree source
+ *
+ * Copyright 2016 Google, Inc
+ */
+
+/dts-v1/;
+#include "rk3288-veyron.dtsi"
+#include "rk3288-veyron-analog-audio.dtsi"
+
+/ {
+	model = "Google Fievel";
+	compatible = "google,veyron-fievel-rev8", "google,veyron-fievel-rev7",
+		     "google,veyron-fievel-rev6", "google,veyron-fievel-rev5",
+		     "google,veyron-fievel-rev4", "google,veyron-fievel-rev3",
+		     "google,veyron-fievel-rev2", "google,veyron-fievel-rev1",
+		     "google,veyron-fievel-rev0", "google,veyron-fievel",
+		     "google,veyron", "rockchip,rk3288";
+
+	/delete-node/ bt-activity;
+
+	ext_gmac: external-gmac-clock {
+		compatible = "fixed-clock";
+		#clock-cells = <0>;
+		clock-frequency = <125000000>;
+		clock-output-names = "ext_gmac";
+	};
+
+	/*
+	 * vcc33_pmuio and vcc33_io is sourced directly from vcc33_sys,
+	 * enabled by vcc_18
+	 */
+	vcc33_io: vcc33-io {
+		compatible = "regulator-fixed";
+		regulator-always-on;
+		regulator-boot-on;
+		regulator-name = "vcc33_io";
+	};
+
+	vcc5_host1: vcc5-host1-regulator {
+		compatible = "regulator-fixed";
+		enable-active-high;
+		gpio = <&gpio5 RK_PC1 GPIO_ACTIVE_HIGH>;
+		pinctrl-names = "default";
+		pinctrl-0 = <&hub_usb1_pwr_en>;
+		regulator-name = "vcc5_host1";
+		regulator-always-on;
+		regulator-boot-on;
+	};
+
+	vcc5_host2: vcc5-host2-regulator {
+		compatible = "regulator-fixed";
+		enable-active-high;
+		gpio = <&gpio5 RK_PC2 GPIO_ACTIVE_HIGH>;
+		pinctrl-names = "default";
+		pinctrl-0 = <&hub_usb2_pwr_en>;
+		regulator-name = "vcc5_host2";
+		regulator-always-on;
+		regulator-boot-on;
+	};
+
+	vcc5v_otg: vcc5v-otg-regulator {
+		compatible = "regulator-fixed";
+		enable-active-high;
+		gpio = <&gpio0 RK_PB4 GPIO_ACTIVE_HIGH>;
+		pinctrl-names = "default";
+		pinctrl-0 = <&usb_otg_pwr_en>;
+		regulator-name = "vcc5_otg";
+		regulator-always-on;
+		regulator-boot-on;
+	};
+};
+
+&gmac {
+	status = "okay";
+
+	assigned-clocks = <&cru SCLK_MAC>;
+	assigned-clock-parents = <&ext_gmac>;
+	clock_in_out = "input";
+	phy-handle = <&ethphy>;
+	phy-mode = "rgmii";
+	phy-supply = <&vcc33_lan>;
+	pinctrl-names = "default";
+	pinctrl-0 = <&rgmii_pins>, <&phy_rst>, <&phy_pmeb>, <&phy_int>;
+	resets = <&cru SRST_MAC>;
+	reset-names = "stmmaceth";
+	rx_delay = <0x10>;
+	tx_delay = <0x30>;
+
+	/* Reset for the RTL8211 PHY which requires a 10-ms reset pulse (low)
+	 * with a 30ms settling time. */
+	snps,reset-gpio = <&gpio4 RK_PB0 0>;
+	snps,reset-active-low;
+	snps,reset-delays-us = <0 10000 30000>;
+	wakeup-source;
+
+	mdio0 {
+		compatible = "snps,dwmac-mdio";
+		#address-cells = <1>;
+		#size-cells = <0>;
+
+		ethphy: ethernet-phy@1 {
+			reg = <1>;
+		};
+	};
+};
+
+&rk808 {
+	dvs-gpios = <&gpio7 RK_PB4 GPIO_ACTIVE_HIGH>,
+		    <&gpio7 RK_PB7 GPIO_ACTIVE_HIGH>;
+	pinctrl-names = "default";
+	pinctrl-0 = <&pmic_int_l &dvs_1 &dvs_2>;
+
+	vcc6-supply = <&vcc33_sys>;
+	vcc10-supply = <&vcc33_sys>;
+	vcc11-supply = <&vcc_5v>;
+	vcc12-supply = <&vcc33_sys>;
+
+	regulators {
+		/delete-node/ LDO_REG1;
+
+		/* According to the schematic, vcc18_lcdt is for
+		 * HDMI_AVDD_1V8
+		 */
+		vcc18_lcdt: LDO_REG2 {
+			regulator-always-on;
+			regulator-boot-on;
+			regulator-min-microvolt = <1800000>;
+			regulator-max-microvolt = <1800000>;
+			regulator-name = "vdd18_lcdt";
+			regulator-state-mem {
+				regulator-on-in-suspend;
+				regulator-suspend-microvolt = <1800000>;
+			};
+		};
+
+		/* This is not a pwren anymore, but the real power supply,
+		 * vdd10_lcd for HDMI_AVDD_1V0
+		 */
+		vdd10_lcd: LDO_REG7 {
+			regulator-always-on;
+			regulator-boot-on;
+			regulator-min-microvolt = <1000000>;
+			regulator-max-microvolt = <1000000>;
+			regulator-name = "vdd10_lcd";
+			regulator-state-mem {
+				regulator-on-in-suspend;
+				regulator-suspend-microvolt = <1000000>;
+			};
+
+		};
+
+		/* for usb camera */
+		vcc33_ccd: LDO_REG8 {
+			regulator-always-on;
+			regulator-boot-on;
+			regulator-min-microvolt = <3300000>;
+			regulator-max-microvolt = <3300000>;
+			regulator-name = "vcc33_ccd";
+			regulator-state-mem {
+				regulator-on-in-suspend;
+				regulator-suspend-microvolt = <3300000>;
+			};
+		};
+
+		vcc33_lan: SWITCH_REG2 {
+			regulator-name = "vcc33_lan";
+		};
+	};
+};
+
+&sdio0 {
+	#address-cells = <1>;
+	#size-cells = <0>;
+
+	btmrvl: btmrvl@2 {
+		compatible = "marvell,sd8897-bt";
+		reg = <2>;
+		interrupt-parent = <&gpio4>;
+		interrupts = <RK_PD7 IRQ_TYPE_LEVEL_LOW>;
+		marvell,wakeup-pin = /bits/ 16 <13>;
+		pinctrl-names = "default";
+		pinctrl-0 = <&bt_host_wake>;
+	};
+};
+
+&vcc50_hdmi {
+	enable-active-high;
+	gpio = <&gpio5 RK_PC3 GPIO_ACTIVE_HIGH>;
+	pinctrl-names = "default";
+	pinctrl-0 = <&vcc50_hdmi_en>;
+};
+
+&vcc_5v {
+	enable-active-high;
+	gpio = <&gpio7 RK_PC5 GPIO_ACTIVE_HIGH>;
+	pinctrl-names = "default";
+	pinctrl-0 = <&drv_5v>;
+};
+
+&pinctrl {
+	pinctrl-names = "default", "sleep";
+	pinctrl-0 = <
+		/* Common for sleep and wake, but no owners */
+		&ddr0_retention
+		&ddrio_pwroff
+		&global_pwroff
+
+		/* Wake only */
+		&bt_dev_wake_awake
+		&pwr_led1_on
+
+		/* For usb bc1.2 */
+		&usb_otg_ilim_sel
+		&usb_usb_ilim_sel
+	>;
+
+	pinctrl-1 = <
+		/* Common for sleep and wake, but no owners */
+		&ddr0_retention
+		&ddrio_pwroff
+		&global_pwroff
+
+		/* Sleep only */
+		&bt_dev_wake_sleep
+		&pwr_led1_blink
+	>;
+
+	buck-5v {
+		drv_5v: drv-5v {
+			rockchip,pins = <7 RK_PC5 RK_FUNC_GPIO &pcfg_pull_none>;
+		};
+	};
+
+	gmac {
+		phy_rst: phy-rst {
+			rockchip,pins = <4 RK_PB0 RK_FUNC_GPIO &pcfg_output_high>;
+		};
+
+		phy_pmeb: phy-pmeb {
+			rockchip,pins = <0 RK_PA7 RK_FUNC_GPIO &pcfg_pull_up>;
+		};
+
+		phy_int: phy-int {
+			rockchip,pins = <0 RK_PB0 RK_FUNC_GPIO &pcfg_pull_up>;
+		};
+	};
+
+	hdmi {
+		vcc50_hdmi_en: vcc50-hdmi-en {
+			rockchip,pins = <5 RK_PC3 RK_FUNC_GPIO &pcfg_pull_none>;
+		};
+	};
+
+	leds {
+		pwr_led1_on: pwr-led1-on {
+			rockchip,pins = <7 RK_PA3 RK_FUNC_GPIO &pcfg_output_low>;
+		};
+
+		pwr_led1_blink: pwr-led1-blink {
+			rockchip,pins = <7 RK_PA3 RK_FUNC_GPIO &pcfg_output_high>;
+		};
+	};
+
+	pmic {
+		dvs_1: dvs-1 {
+			rockchip,pins = <7 RK_PB4 RK_FUNC_GPIO &pcfg_pull_down>;
+		};
+
+		dvs_2: dvs-2 {
+			rockchip,pins = <7 RK_PB7 RK_FUNC_GPIO &pcfg_pull_down>;
+		};
+	};
+
+	usb-bc12 {
+		usb_otg_ilim_sel: usb-otg-ilim-sel {
+			rockchip,pins = <6 RK_PC1 RK_FUNC_GPIO &pcfg_output_low>;
+		};
+
+		usb_usb_ilim_sel: usb-usb-ilim-sel {
+			rockchip,pins = <5 RK_PB7 RK_FUNC_GPIO &pcfg_output_low>;
+		};
+	};
+
+	usb-host {
+		hub_usb1_pwr_en: hub_usb1_pwr_en {
+			rockchip,pins = <5 RK_PC2 RK_FUNC_GPIO &pcfg_pull_none>;
+		};
+
+		hub_usb2_pwr_en: hub_usb2_pwr_en {
+			rockchip,pins = <5 RK_PB6 RK_FUNC_GPIO &pcfg_pull_none>;
+		};
+
+		usb_otg_pwr_en: usb_otg_pwr_en {
+			rockchip,pins = <0 RK_PB4 RK_FUNC_GPIO &pcfg_pull_none>;
+		};
+	};
+};
-- 
2.22.0.709.g102302147b-goog

^ permalink raw reply related

* [PATCH v3 5/5] ARM: dts: rockchip: add veyron-tiger board
From: Matthias Kaehlcke @ 2019-07-25 16:26 UTC (permalink / raw)
  To: Rob Herring, Mark Rutland, Heiko Stuebner
  Cc: devicetree, linux-arm-kernel, linux-rockchip, linux-kernel,
	Matthias Kaehlcke
In-Reply-To: <20190725162642.250709-1-mka@chromium.org>

Also known as the AOpen Chromebase Mini.

tiger and fievel are share the same board, tiger has a display and
touchscreen, fievel not. Use the fievel .dts as base and add the
extra bits.

Signed-off-by: Matthias Kaehlcke <mka@chromium.org>
---
Changes in v3:
- patch added to the series
---
 arch/arm/boot/dts/Makefile                |   1 +
 arch/arm/boot/dts/rk3288-veyron-tiger.dts | 125 ++++++++++++++++++++++
 2 files changed, 126 insertions(+)
 create mode 100644 arch/arm/boot/dts/rk3288-veyron-tiger.dts

diff --git a/arch/arm/boot/dts/Makefile b/arch/arm/boot/dts/Makefile
index 9fd1e075c624..64b08922e75d 100644
--- a/arch/arm/boot/dts/Makefile
+++ b/arch/arm/boot/dts/Makefile
@@ -927,6 +927,7 @@ dtb-$(CONFIG_ARCH_ROCKCHIP) += \
 	rk3288-veyron-minnie.dtb \
 	rk3288-veyron-pinky.dtb \
 	rk3288-veyron-speedy.dtb \
+	rk3288-veyron-tiger.dtb \
 	rk3288-vyasa.dtb
 dtb-$(CONFIG_ARCH_S3C24XX) += \
 	s3c2416-smdk2416.dtb
diff --git a/arch/arm/boot/dts/rk3288-veyron-tiger.dts b/arch/arm/boot/dts/rk3288-veyron-tiger.dts
new file mode 100644
index 000000000000..fae26d530841
--- /dev/null
+++ b/arch/arm/boot/dts/rk3288-veyron-tiger.dts
@@ -0,0 +1,125 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+/*
+ * Google Veyron Tiger Rev 0+ board device tree source
+ *
+ * Copyright 2016 Google, Inc
+ */
+
+/dts-v1/;
+#include "rk3288-veyron-fievel.dts"
+#include "rk3288-veyron-edp.dtsi"
+
+/ {
+	model = "Google Tiger";
+	compatible = "google,veyron-tiger-rev8", "google,veyron-tiger-rev7",
+		     "google,veyron-tiger-rev6", "google,veyron-tiger-rev5",
+		     "google,veyron-tiger-rev4", "google,veyron-tiger-rev3",
+		     "google,veyron-tiger-rev2", "google,veyron-tiger-rev1",
+		     "google,veyron-tiger-rev0", "google,veyron-tiger",
+		     "google,veyron", "rockchip,rk3288";
+
+	/delete-node/ vcc18-lcd;
+
+	vccsys: vccsys {
+		compatible = "regulator-fixed";
+		regulator-name = "vccsys";
+		regulator-boot-on;
+		regulator-always-on;
+	};
+};
+
+&backlight {
+	/* Tiger panel PWM must be >= 1%, so start non-zero brightness at 3 */
+	brightness-levels = <
+		  0   3   4   5   6   7
+		  8   9  10  11  12  13  14  15
+		 16  17  18  19  20  21  22  23
+		 24  25  26  27  28  29  30  31
+		 32  33  34  35  36  37  38  39
+		 40  41  42  43  44  45  46  47
+		 48  49  50  51  52  53  54  55
+		 56  57  58  59  60  61  62  63
+		 64  65  66  67  68  69  70  71
+		 72  73  74  75  76  77  78  79
+		 80  81  82  83  84  85  86  87
+		 88  89  90  91  92  93  94  95
+		 96  97  98  99 100 101 102 103
+		104 105 106 107 108 109 110 111
+		112 113 114 115 116 117 118 119
+		120 121 122 123 124 125 126 127
+		128 129 130 131 132 133 134 135
+		136 137 138 139 140 141 142 143
+		144 145 146 147 148 149 150 151
+		152 153 154 155 156 157 158 159
+		160 161 162 163 164 165 166 167
+		168 169 170 171 172 173 174 175
+		176 177 178 179 180 181 182 183
+		184 185 186 187 188 189 190 191
+		192 193 194 195 196 197 198 199
+		200 201 202 203 204 205 206 207
+		208 209 210 211 212 213 214 215
+		216 217 218 219 220 221 222 223
+		224 225 226 227 228 229 230 231
+		232 233 234 235 236 237 238 239
+		240 241 242 243 244 245 246 247
+		248 249 250 251 252 253 254 255>;
+};
+
+&backlight_regulator {
+	vin-supply = <&vccsys>;
+};
+
+&i2c3 {
+	status = "okay";
+
+	clock-frequency = <400000>;
+	i2c-scl-falling-time-ns = <50>;
+	i2c-scl-rising-time-ns = <300>;
+
+	touchscreen@10 {
+		compatible = "elan,ekth3500";
+		reg = <0x10>;
+		interrupt-parent = <&gpio2>;
+		interrupts = <RK_PB6 IRQ_TYPE_EDGE_FALLING>;
+		pinctrl-names = "default";
+		pinctrl-0 = <&touch_int &touch_rst>;
+		reset-gpios = <&gpio2 RK_PB7 GPIO_ACTIVE_LOW>;
+		vcc33-supply = <&vcc33_io>;
+		vccio-supply = <&vcc33_io>;
+		wakeup-source;
+	};
+};
+
+&panel {
+	compatible = "auo,b101ean01", "simple-panel";
+
+	/delete-node/ panel-timing;
+
+	panel-timing {
+		clock-frequency = <66666667>;
+		hactive = <1280>;
+		hfront-porch = <18>;
+		hback-porch = <21>;
+		hsync-len = <32>;
+		vactive = <800>;
+		vfront-porch = <4>;
+		vback-porch = <8>;
+		vsync-len = <18>;
+	};
+};
+
+&pinctrl {
+	lcd {
+		/delete-node/ avdd-1v8-disp-en;
+	};
+
+	touchscreen {
+		touch_int: touch-int {
+			rockchip,pins = <2 RK_PB6 RK_FUNC_GPIO &pcfg_pull_none>;
+		};
+
+		touch_rst: touch-rst {
+			rockchip,pins = <2 RK_PB7 RK_FUNC_GPIO &pcfg_pull_none>;
+		};
+	};
+};
-- 
2.22.0.709.g102302147b-goog

^ permalink raw reply related

* Re: [PATCH v3 1/5] ARM: dts: rockchip: move rk3288-veryon display settings into a separate file
From: Doug Anderson @ 2019-07-25 16:48 UTC (permalink / raw)
  To: Matthias Kaehlcke
  Cc: Rob Herring, Mark Rutland, Heiko Stuebner, devicetree, Linux ARM,
	open list:ARM/Rockchip SoC..., LKML
In-Reply-To: <20190725162642.250709-2-mka@chromium.org>

Hi,

On Thu, Jul 25, 2019 at 9:26 AM Matthias Kaehlcke <mka@chromium.org> wrote:
>
> The chromebook .dtsi file contains common settings for veyron
> Chromebooks with eDP displays. Some veyron devices with a display
> aren't Chromebooks (e.g. 'tiger' aka 'AOpen Chromebase Mini'), move
> display related bits from the chromebook .dtsi into a separate file
> to avoid redundant DT settings.
>
> The new file is included from the chromebook .dtsi and can be
> included by non-Chromebook devices with a display.
>
> Signed-off-by: Matthias Kaehlcke <mka@chromium.org>
> ---
> Changes in v3:
> - allow MIT license
> - move pinctrl section to the bottom
>
> Changes in v2:
> - rebased on v5.4-armsoc/dts32 (0d19541e3b45)
> ---
>  .../boot/dts/rk3288-veyron-chromebook.dtsi    | 115 +---------------
>  arch/arm/boot/dts/rk3288-veyron-edp.dtsi      | 124 ++++++++++++++++++
>  2 files changed, 125 insertions(+), 114 deletions(-)

Reviewed-by: Douglas Anderson <dianders@chromium.org>

^ permalink raw reply

* Re: [PATCH v3 3/5] dt-bindings: ARM: dts: rockchip: Add bindings for rk3288-veyron-{fievel,tiger}
From: Doug Anderson @ 2019-07-25 16:53 UTC (permalink / raw)
  To: Matthias Kaehlcke
  Cc: Rob Herring, Mark Rutland, Heiko Stuebner, devicetree, Linux ARM,
	open list:ARM/Rockchip SoC..., LKML
In-Reply-To: <20190725162642.250709-4-mka@chromium.org>

Hi,

On Thu, Jul 25, 2019 at 9:27 AM Matthias Kaehlcke <mka@chromium.org> wrote:
>
> Fievel is a Chromebox and Tiger a Chromebase with a 10" display and
> touchscreen. Tiger and Fievel are based on the same board.
>
> Signed-off-by: Matthias Kaehlcke <mka@chromium.org>
> ---
> Changes in v3:
> - patch added to the series
> ---
>  .../devicetree/bindings/arm/rockchip.yaml     | 30 +++++++++++++++++++
>  1 file changed, 30 insertions(+)

Reviewed-by: Douglas Anderson <dianders@chromium.org>

^ permalink raw reply

* Re: [PATCH] arm64: dts: fast models: Increase clcd's max-memory-bandwidth
From: Kevin Brodsky @ 2019-07-25 16:58 UTC (permalink / raw)
  To: Robin Murphy, linux-arm-kernel
  Cc: devicetree, Pawel Moll, Ruben Ayrapetyan, Linus Walleij,
	Liviu Dudau, dri-devel, Sudeep Holla, Brian Starkey
In-Reply-To: <042d5c3d-96fe-5466-3869-a0a3a08b964d@arm.com>

On 25/07/2019 16:15, Robin Murphy wrote:
> Hi Kevin,

Hi Robin,

> On 25/07/2019 15:50, Kevin Brodsky wrote:
>> It may be desirable on certain platforms, such as Android, to
>> use 32bpp buffers. Since there is no clear bandwidth limit for the
>> CLCD component on the fast model, let's increase
>> max-memory-bandwidth to allow using 32bpp buffers.
> Given that the property is optional anyway, would it hurt to just remove
> it? After trying to dig up any relevant internal email history, it's
> still far from clear how and why it got here in the first place.

Very good point, I hadn't realised it was an optional property. Removing it 
completely seems to work fine. I'll send a v2 removing it from both fvp-base-revc.dts 
and rtsm_ve-motherboard.dtsi. Thanks!

Kevin

> Robin.
>
>> Reported-by: Ruben Ayrapetyan <ruben.ayrapetyan@arm.com>
>> Signed-off-by: Kevin Brodsky <kevin.brodsky@arm.com>
>> ---
>>    arch/arm64/boot/dts/arm/fvp-base-revc.dts | 2 +-
>>    1 file changed, 1 insertion(+), 1 deletion(-)
>>
>> diff --git a/arch/arm64/boot/dts/arm/fvp-base-revc.dts b/arch/arm64/boot/dts/arm/fvp-base-revc.dts
>> index 687707020ec1..3aee49ed6d88 100644
>> --- a/arch/arm64/boot/dts/arm/fvp-base-revc.dts
>> +++ b/arch/arm64/boot/dts/arm/fvp-base-revc.dts
>> @@ -269,7 +269,7 @@
>>    		motherboard {
>>    			iofpga@3,00000000 {
>>    				clcd@1f0000 {
>> -					max-memory-bandwidth = <130000000>; /* 16bpp @ 63.5MHz */
>> +					max-memory-bandwidth = <260000000>; /* 32bpp @ 63.5MHz */
>>    				};
>>    			};
>>    		};
>>

^ permalink raw reply

* [PATCH v2 0/6] ASoC: improve codec to codec link support
From: Jerome Brunet @ 2019-07-25 16:59 UTC (permalink / raw)
  To: Mark Brown, Liam Girdwood, Kevin Hilman
  Cc: Jerome Brunet, alsa-devel, devicetree, linux-kernel,
	linux-amlogic

As explained in this previous series [0], on Amlogic, we are using codec to
codec links to deal with the glue which is between the i2s backends and the
synopsys hdmi controller.

This worked well until I tried to .get_eld() support in the dw-hdmi-i2s
driver.  Doing so adds channel mapping controls to the codec. This shown
several problem

1) .pcm_new() is not called on codec to codec links.
   struct snd_soc_pcm_runtime do not even have a valid .pcm
2) struct snd_pcm_substream and struct snd_pcm_runtime are ephemeral
   This is a problem if a control needs to access them

The goal of this patchset is to resolve the above issues and improve the
codec to codec link support enough to correctly handle the hdmi-codec

The support of these codec to codec links could probably be improved in the
future to behave like any other link and use soc_pcm_open(),
soc_pcm_hw_params(), etc...

The challenge lies in the dapm mutex. The soc_pcm call dapm function locking
this mutex but the dapm mutex is already held in snd_soc_dai_link_event()

Changes since v1 [1]:
* Fix rebase on Murimoto-san's patches
* Allocate params dynamically again and refactor the pre_pmu code to
  simplify the error handling and rollback a bit

[0]: https://lkml.kernel.org/r/20190515131858.32130-1-jbrunet@baylibre.com
[1]: https://lkml.kernel.org/r/20190724162405.6574-1-jbrunet@baylibre.com

Jerome Brunet (6):
  ASoC: codec2codec: run callbacks in order
  ASoC: codec2codec: name link using stream direction
  ASoC: codec2codec: deal with params when necessary
  ASoC: create pcm for codec2codec links as well
  ASoC: codec2codec: remove ephemeral variables
  ASoC: codec2codec: fill some of the runtime stream parameters

 sound/soc/soc-core.c |  42 +++------
 sound/soc/soc-dapm.c | 220 +++++++++++++++++++++++++++----------------
 sound/soc/soc-pcm.c  |  35 ++++++-
 3 files changed, 182 insertions(+), 115 deletions(-)

-- 
2.21.0

^ permalink raw reply

* [PATCH v2 1/6] ASoC: codec2codec: run callbacks in order
From: Jerome Brunet @ 2019-07-25 16:59 UTC (permalink / raw)
  To: Mark Brown, Liam Girdwood, Kevin Hilman
  Cc: Jerome Brunet, alsa-devel, devicetree, linux-kernel,
	linux-amlogic
In-Reply-To: <20190725165949.29699-1-jbrunet@baylibre.com>

When handling dai_link events on codec to codec links, run all .startup()
callbacks on sinks and sources before running any .hw_params(). Same goes
for hw_free() and shutdown(). This is closer to the behavior of regular
dai links

Signed-off-by: Jerome Brunet <jbrunet@baylibre.com>
---
 sound/soc/soc-dapm.c | 36 +++++++++++++++++++++++++++---------
 1 file changed, 27 insertions(+), 9 deletions(-)

diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c
index 1d04612601ad..034b31fd2ecb 100644
--- a/sound/soc/soc-dapm.c
+++ b/sound/soc/soc-dapm.c
@@ -3835,11 +3835,6 @@ static int snd_soc_dai_link_event(struct snd_soc_dapm_widget *w,
 				goto out;
 			}
 			source->active++;
-			ret = snd_soc_dai_hw_params(source, &substream, params);
-			if (ret < 0)
-				goto out;
-
-			dapm_update_dai_unlocked(&substream, params, source);
 		}
 
 		substream.stream = SNDRV_PCM_STREAM_PLAYBACK;
@@ -3853,6 +3848,23 @@ static int snd_soc_dai_link_event(struct snd_soc_dapm_widget *w,
 				goto out;
 			}
 			sink->active++;
+		}
+
+		substream.stream = SNDRV_PCM_STREAM_CAPTURE;
+		snd_soc_dapm_widget_for_each_source_path(w, path) {
+			source = path->source->priv;
+
+			ret = snd_soc_dai_hw_params(source, &substream, params);
+			if (ret < 0)
+				goto out;
+
+			dapm_update_dai_unlocked(&substream, params, source);
+		}
+
+		substream.stream = SNDRV_PCM_STREAM_PLAYBACK;
+		snd_soc_dapm_widget_for_each_sink_path(w, path) {
+			sink = path->sink->priv;
+
 			ret = snd_soc_dai_hw_params(sink, &substream, params);
 			if (ret < 0)
 				goto out;
@@ -3889,9 +3901,18 @@ static int snd_soc_dai_link_event(struct snd_soc_dapm_widget *w,
 		substream.stream = SNDRV_PCM_STREAM_CAPTURE;
 		snd_soc_dapm_widget_for_each_source_path(w, path) {
 			source = path->source->priv;
-
 			snd_soc_dai_hw_free(source, &substream);
+		}
+
+		substream.stream = SNDRV_PCM_STREAM_PLAYBACK;
+		snd_soc_dapm_widget_for_each_sink_path(w, path) {
+			sink = path->sink->priv;
+			snd_soc_dai_hw_free(sink, &substream);
+		}
 
+		substream.stream = SNDRV_PCM_STREAM_CAPTURE;
+		snd_soc_dapm_widget_for_each_source_path(w, path) {
+			source = path->source->priv;
 			source->active--;
 			snd_soc_dai_shutdown(source, &substream);
 		}
@@ -3899,9 +3920,6 @@ static int snd_soc_dai_link_event(struct snd_soc_dapm_widget *w,
 		substream.stream = SNDRV_PCM_STREAM_PLAYBACK;
 		snd_soc_dapm_widget_for_each_sink_path(w, path) {
 			sink = path->sink->priv;
-
-			snd_soc_dai_hw_free(sink, &substream);
-
 			sink->active--;
 			snd_soc_dai_shutdown(sink, &substream);
 		}
-- 
2.21.0

^ permalink raw reply related

* [PATCH v2 2/6] ASoC: codec2codec: name link using stream direction
From: Jerome Brunet @ 2019-07-25 16:59 UTC (permalink / raw)
  To: Mark Brown, Liam Girdwood, Kevin Hilman
  Cc: Jerome Brunet, alsa-devel, devicetree, linux-kernel,
	linux-amlogic
In-Reply-To: <20190725165949.29699-1-jbrunet@baylibre.com>

At the moment, codec to codec dai link widgets are named after the
cpu dai and the 1st codec valid on the link. This might be confusing
if there is multiple valid codecs on the link for one stream
direction.

Instead, use the dai link name and the stream direction to name the
the dai link widget

Signed-off-by: Jerome Brunet <jbrunet@baylibre.com>
---
 sound/soc/soc-dapm.c | 12 ++++--------
 1 file changed, 4 insertions(+), 8 deletions(-)

diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c
index 034b31fd2ecb..7db4abd9a0a5 100644
--- a/sound/soc/soc-dapm.c
+++ b/sound/soc/soc-dapm.c
@@ -4056,8 +4056,7 @@ snd_soc_dapm_alloc_kcontrol(struct snd_soc_card *card,
 
 static struct snd_soc_dapm_widget *
 snd_soc_dapm_new_dai(struct snd_soc_card *card, struct snd_soc_pcm_runtime *rtd,
-		     struct snd_soc_dapm_widget *source,
-		     struct snd_soc_dapm_widget *sink)
+		     char *id)
 {
 	struct snd_soc_dapm_widget template;
 	struct snd_soc_dapm_widget *w;
@@ -4067,7 +4066,7 @@ snd_soc_dapm_new_dai(struct snd_soc_card *card, struct snd_soc_pcm_runtime *rtd,
 	int ret;
 
 	link_name = devm_kasprintf(card->dev, GFP_KERNEL, "%s-%s",
-				   source->name, sink->name);
+				   rtd->dai_link->name, id);
 	if (!link_name)
 		return ERR_PTR(-ENOMEM);
 
@@ -4247,15 +4246,13 @@ static void dapm_connect_dai_link_widgets(struct snd_soc_card *card,
 	}
 
 	for_each_rtd_codec_dai(rtd, i, codec_dai) {
-
 		/* connect BE DAI playback if widgets are valid */
 		codec = codec_dai->playback_widget;
 
 		if (playback_cpu && codec) {
 			if (!playback) {
 				playback = snd_soc_dapm_new_dai(card, rtd,
-								playback_cpu,
-								codec);
+								"playback");
 				if (IS_ERR(playback)) {
 					dev_err(rtd->dev,
 						"ASoC: Failed to create DAI %s: %ld\n",
@@ -4284,8 +4281,7 @@ static void dapm_connect_dai_link_widgets(struct snd_soc_card *card,
 		if (codec && capture_cpu) {
 			if (!capture) {
 				capture = snd_soc_dapm_new_dai(card, rtd,
-							       codec,
-							       capture_cpu);
+							       "capture");
 				if (IS_ERR(capture)) {
 					dev_err(rtd->dev,
 						"ASoC: Failed to create DAI %s: %ld\n",
-- 
2.21.0

^ permalink raw reply related

* [PATCH v2 3/6] ASoC: codec2codec: deal with params when necessary
From: Jerome Brunet @ 2019-07-25 16:59 UTC (permalink / raw)
  To: Mark Brown, Liam Girdwood, Kevin Hilman
  Cc: Jerome Brunet, alsa-devel, devicetree, linux-kernel,
	linux-amlogic
In-Reply-To: <20190725165949.29699-1-jbrunet@baylibre.com>

When there is an event on codec to codec dai_link, we only need to deal
with params if the event is SND_SOC_DAPM_PRE_PMU, when .hw_params() is
called. For the other events, it is useless.

Also, dealing with the codec to codec params just before calling
.hw_params() callbacks give change to either party on the link to alter
params content in .startup(), which might be useful in some cases

Signed-off-by: Jerome Brunet <jbrunet@baylibre.com>
---
 sound/soc/soc-dapm.c | 159 +++++++++++++++++++++++++------------------
 1 file changed, 92 insertions(+), 67 deletions(-)

diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c
index 7db4abd9a0a5..6dcaf9ff6eb5 100644
--- a/sound/soc/soc-dapm.c
+++ b/sound/soc/soc-dapm.c
@@ -3764,25 +3764,59 @@ int snd_soc_dapm_new_controls(struct snd_soc_dapm_context *dapm,
 }
 EXPORT_SYMBOL_GPL(snd_soc_dapm_new_controls);
 
-static int snd_soc_dai_link_event(struct snd_soc_dapm_widget *w,
-				  struct snd_kcontrol *kcontrol, int event)
+static int
+snd_soc_dai_link_event_pre_pmu(struct snd_soc_dapm_widget *w,
+			       struct snd_pcm_substream *substream)
 {
 	struct snd_soc_dapm_path *path;
 	struct snd_soc_dai *source, *sink;
-	struct snd_soc_pcm_runtime *rtd = w->priv;
-	const struct snd_soc_pcm_stream *config;
-	struct snd_pcm_substream substream;
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
 	struct snd_pcm_hw_params *params = NULL;
-	struct snd_pcm_runtime *runtime = NULL;
+	const struct snd_soc_pcm_stream *config = NULL;
 	unsigned int fmt;
-	int ret = 0;
+	int ret;
 
-	config = rtd->dai_link->params + rtd->params_select;
+	params = kzalloc(sizeof(*params), GFP_KERNEL);
+	if (!params)
+		return -ENOMEM;
 
-	if (WARN_ON(!config) ||
-	    WARN_ON(list_empty(&w->edges[SND_SOC_DAPM_DIR_OUT]) ||
-		    list_empty(&w->edges[SND_SOC_DAPM_DIR_IN])))
-		return -EINVAL;
+	substream->stream = SNDRV_PCM_STREAM_CAPTURE;
+	snd_soc_dapm_widget_for_each_source_path(w, path) {
+		source = path->source->priv;
+
+		ret = snd_soc_dai_startup(source, substream);
+		if (ret < 0) {
+			dev_err(source->dev,
+				"ASoC: startup() failed: %d\n", ret);
+			goto out;
+		}
+		source->active++;
+	}
+
+	substream->stream = SNDRV_PCM_STREAM_PLAYBACK;
+	snd_soc_dapm_widget_for_each_sink_path(w, path) {
+		sink = path->sink->priv;
+
+		ret = snd_soc_dai_startup(sink, substream);
+		if (ret < 0) {
+			dev_err(sink->dev,
+				"ASoC: startup() failed: %d\n", ret);
+			goto out;
+		}
+		sink->active++;
+	}
+
+	/*
+	 * Note: getting the config after .startup() gives a chance to
+	 * either party on the link to alter the configuration if
+	 * necessary
+	 */
+	config = rtd->dai_link->params + rtd->params_select;
+	if (WARN_ON(!config)) {
+		dev_err(w->dapm->dev, "ASoC: link config missing\n");
+		ret = -EINVAL;
+		goto out;
+	}
 
 	/* Be a little careful as we don't want to overflow the mask array */
 	if (config->formats) {
@@ -3790,27 +3824,62 @@ static int snd_soc_dai_link_event(struct snd_soc_dapm_widget *w,
 	} else {
 		dev_warn(w->dapm->dev, "ASoC: Invalid format %llx specified\n",
 			 config->formats);
-		fmt = 0;
-	}
 
-	/* Currently very limited parameter selection */
-	params = kzalloc(sizeof(*params), GFP_KERNEL);
-	if (!params) {
-		ret = -ENOMEM;
+		ret = -EINVAL;
 		goto out;
 	}
-	snd_mask_set(hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT), fmt);
 
+	snd_mask_set(hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT), fmt);
 	hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE)->min =
 		config->rate_min;
 	hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE)->max =
 		config->rate_max;
-
 	hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS)->min
 		= config->channels_min;
 	hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS)->max
 		= config->channels_max;
 
+	substream->stream = SNDRV_PCM_STREAM_CAPTURE;
+	snd_soc_dapm_widget_for_each_source_path(w, path) {
+		source = path->source->priv;
+
+		ret = snd_soc_dai_hw_params(source, substream, params);
+		if (ret < 0)
+			goto out;
+
+		dapm_update_dai_unlocked(substream, params, source);
+	}
+
+	substream->stream = SNDRV_PCM_STREAM_PLAYBACK;
+	snd_soc_dapm_widget_for_each_sink_path(w, path) {
+		sink = path->sink->priv;
+
+		ret = snd_soc_dai_hw_params(sink, substream, params);
+		if (ret < 0)
+			goto out;
+
+		dapm_update_dai_unlocked(substream, params, sink);
+	}
+
+out:
+	kfree(params);
+	return 0;
+}
+
+static int snd_soc_dai_link_event(struct snd_soc_dapm_widget *w,
+				  struct snd_kcontrol *kcontrol, int event)
+{
+	struct snd_soc_dapm_path *path;
+	struct snd_soc_dai *source, *sink;
+	struct snd_soc_pcm_runtime *rtd = w->priv;
+	struct snd_pcm_substream substream;
+	struct snd_pcm_runtime *runtime = NULL;
+	int ret = 0;
+
+	if (WARN_ON(list_empty(&w->edges[SND_SOC_DAPM_DIR_OUT]) ||
+		    list_empty(&w->edges[SND_SOC_DAPM_DIR_IN])))
+		return -EINVAL;
+
 	memset(&substream, 0, sizeof(substream));
 
 	/* Allocate a dummy snd_pcm_runtime for startup() and other ops() */
@@ -3824,53 +3893,10 @@ static int snd_soc_dai_link_event(struct snd_soc_dapm_widget *w,
 
 	switch (event) {
 	case SND_SOC_DAPM_PRE_PMU:
-		substream.stream = SNDRV_PCM_STREAM_CAPTURE;
-		snd_soc_dapm_widget_for_each_source_path(w, path) {
-			source = path->source->priv;
-
-			ret = snd_soc_dai_startup(source, &substream);
-			if (ret < 0) {
-				dev_err(source->dev,
-					"ASoC: startup() failed: %d\n", ret);
-				goto out;
-			}
-			source->active++;
-		}
-
-		substream.stream = SNDRV_PCM_STREAM_PLAYBACK;
-		snd_soc_dapm_widget_for_each_sink_path(w, path) {
-			sink = path->sink->priv;
-
-			ret = snd_soc_dai_startup(sink, &substream);
-			if (ret < 0) {
-				dev_err(sink->dev,
-					"ASoC: startup() failed: %d\n", ret);
-				goto out;
-			}
-			sink->active++;
-		}
-
-		substream.stream = SNDRV_PCM_STREAM_CAPTURE;
-		snd_soc_dapm_widget_for_each_source_path(w, path) {
-			source = path->source->priv;
-
-			ret = snd_soc_dai_hw_params(source, &substream, params);
-			if (ret < 0)
-				goto out;
-
-			dapm_update_dai_unlocked(&substream, params, source);
-		}
-
-		substream.stream = SNDRV_PCM_STREAM_PLAYBACK;
-		snd_soc_dapm_widget_for_each_sink_path(w, path) {
-			sink = path->sink->priv;
-
-			ret = snd_soc_dai_hw_params(sink, &substream, params);
-			if (ret < 0)
-				goto out;
+		ret = snd_soc_dai_link_event_pre_pmu(w, &substream);
+		if (ret < 0)
+			goto out;
 
-			dapm_update_dai_unlocked(&substream, params, sink);
-		}
 		break;
 
 	case SND_SOC_DAPM_POST_PMU:
@@ -3932,7 +3958,6 @@ static int snd_soc_dai_link_event(struct snd_soc_dapm_widget *w,
 
 out:
 	kfree(runtime);
-	kfree(params);
 	return ret;
 }
 
-- 
2.21.0

^ permalink raw reply related


This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox