Linux-ARM-Kernel Archive on lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v4 08/15] drm/sun4i: Add LVDS support
From: Chen-Yu Tsai @ 2017-12-14  3:42 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <b64644e9397ec437ec4d3d16be585b22086cf615.1512662253.git-series.maxime.ripard@free-electrons.com>

On Thu, Dec 7, 2017 at 11:58 PM, Maxime Ripard
<maxime.ripard@free-electrons.com> wrote:
> The TCON supports the LVDS interface to output to a panel or a bridge.
> Let's add support for it.
>
> Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>
> ---
>  drivers/gpu/drm/sun4i/Makefile     |   1 +-
>  drivers/gpu/drm/sun4i/sun4i_lvds.c | 177 ++++++++++++++++++++++-
>  drivers/gpu/drm/sun4i/sun4i_lvds.h |  18 ++-
>  drivers/gpu/drm/sun4i/sun4i_tcon.c | 242 +++++++++++++++++++++++++++++-
>  drivers/gpu/drm/sun4i/sun4i_tcon.h |  29 ++++-
>  5 files changed, 465 insertions(+), 2 deletions(-)
>  create mode 100644 drivers/gpu/drm/sun4i/sun4i_lvds.c
>  create mode 100644 drivers/gpu/drm/sun4i/sun4i_lvds.h
>

[...]

> diff --git a/drivers/gpu/drm/sun4i/sun4i_lvds.h b/drivers/gpu/drm/sun4i/sun4i_lvds.h
> new file mode 100644
> index 000000000000..1b8fad4b82c3
> --- /dev/null
> +++ b/drivers/gpu/drm/sun4i/sun4i_lvds.h
> @@ -0,0 +1,18 @@
> +/*
> + * Copyright (C) 2015 NextThing Co
> + * Copyright (C) 2015-2017 Free Electrons
> + *
> + * Maxime Ripard <maxime.ripard@free-electrons.com>
> + *
> + * This program is free software; you can redistribute it and/or
> + * modify it under the terms of the GNU General Public License as
> + * published by the Free Software Foundation; either version 2 of
> + * the License, or (at your option) any later version.
> + */

SPDX?

> +
> +#ifndef _SUN4I_LVDS_H_
> +#define _SUN4I_LVDS_H_
> +
> +int sun4i_lvds_init(struct drm_device *drm, struct sun4i_tcon *tcon);
> +
> +#endif /* _SUN4I_LVDS_H_ */
> diff --git a/drivers/gpu/drm/sun4i/sun4i_tcon.c b/drivers/gpu/drm/sun4i/sun4i_tcon.c
> index 46e28ca1f676..777c7348d0cf 100644
> --- a/drivers/gpu/drm/sun4i/sun4i_tcon.c
> +++ b/drivers/gpu/drm/sun4i/sun4i_tcon.c

[...]

> @@ -698,6 +873,54 @@ static int sun4i_tcon_bind(struct device *dev, struct device *master,
>                 return ret;
>         }
>
> +       /*
> +        * This can only be made optional since we've had DT nodes
> +        * without the LVDS reset properties.
> +        *
> +        * If the property is missing, just disable LVDS, and print a
> +        * warning.
> +        */
> +       tcon->lvds_rst = devm_reset_control_get_optional(dev, "lvds");
> +       if (IS_ERR(tcon->lvds_rst)) {
> +               dev_err(dev, "Couldn't get our reset line\n");
> +               return PTR_ERR(tcon->lvds_rst);
> +       } else if (tcon->lvds_rst) {
> +               has_lvds_rst = true;
> +               reset_control_reset(tcon->lvds_rst);
> +       } else {
> +               has_lvds_rst = false;
> +       }
> +
> +       /*
> +        * This can only be made optional since we've had DT nodes
> +        * without the LVDS reset properties.
> +        *
> +        * If the property is missing, just disable LVDS, and print a
> +        * warning.
> +        */
> +       if (tcon->quirks->has_lvds_pll) {

Care to change these names to match the DT property as well?

[...]

> diff --git a/drivers/gpu/drm/sun4i/sun4i_tcon.h b/drivers/gpu/drm/sun4i/sun4i_tcon.h
> index bd3ad7684870..23db06cdc461 100644
> --- a/drivers/gpu/drm/sun4i/sun4i_tcon.h
> +++ b/drivers/gpu/drm/sun4i/sun4i_tcon.h

[...]

> @@ -149,6 +173,7 @@ struct sun4i_tcon;
>
>  struct sun4i_tcon_quirks {
>         bool    has_channel_1;  /* a33 does not have channel 1 */
> +       bool    has_lvds_pll;   /* Can we mux the LVDS clock to a PLL? */

This could then read "Does LVDS clock have parent other than TCON clock?"

Otherwise,

Reviewed-by: Chen-Yu Tsai <wens@csie.org>

Also see my other (late) reply to the previous version.

>         bool    needs_de_be_mux; /* sun6i needs mux to select backend */
>
>         /* callback to handle tcon muxing options */
> @@ -167,6 +192,9 @@ struct sun4i_tcon {
>         struct clk                      *sclk0;
>         struct clk                      *sclk1;
>
> +       /* Possible mux for the LVDS clock */
> +       struct clk                      *lvds_pll;
> +
>         /* Pixel clock */
>         struct clk                      *dclk;
>         u8                              dclk_max_div;
> @@ -174,6 +202,7 @@ struct sun4i_tcon {
>
>         /* Reset control */
>         struct reset_control            *lcd_rst;
> +       struct reset_control            *lvds_rst;
>
>         struct drm_panel                *panel;
>
> --
> git-series 0.9.1

^ permalink raw reply

* [PATCH v4 13/15] ARM: dts: sun8i: a83t: Add the PWM pin group
From: Chen-Yu Tsai @ 2017-12-14  3:44 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <b58547cd03f88c65162f362361023b44a4b6fc89.1512662253.git-series.maxime.ripard@free-electrons.com>

On Thu, Dec 7, 2017 at 11:58 PM, Maxime Ripard
<maxime.ripard@free-electrons.com> wrote:
> The A83T has a PWM that can be output from the SoC. Let's add a pinctrl
> group for it.
>
> Reviewed-by: Chen-Yu Tsai <wens@csie.org>
> Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>

Might as well just squash this with patch 11, and enforce it by default.

ChenYu

^ permalink raw reply

* [PATCH v2 0/3] ARM: sun8i: a83t: Add support for I2S and I2C
From: Chen-Yu Tsai @ 2017-12-14  4:23 UTC (permalink / raw)
  To: linux-arm-kernel

Hi everyone,

This is v2 of my A83T I2S and I2C support series.

Changes since v1:

  - Dropped ASoC patch that was merged
  - Added SoC-specific compatible strings for I2C controllers
  - Added Maxime's Acked-by

This series adds support for I2S and I2C on the Allwinner A83T SoC.
The I2S controllers are similar to the ones found on the A31. However
the TX FIFO and interrupt status registers were swapped around. This
seems to be a recurring theme for the audio related hardware blocks.

Patch 1 adds device nodes and default pinmux settings for the I2S
controllers.

Patch 2 adds device nodes and default pinmux settings for the I2C
controllers.

Patch 3 is an example of a PCM5122 codec tied to I2C2 and I2S1 over
the GPIO header of the Banana Pi M3. This patch should not be merged.

Please have a look.

Regards
ChenYu

Chen-Yu Tsai (3):
  ARM: dts: sun8i: a83t: Add I2S controller device nodes
  ARM: dts: sun8i: a83t: Add I2C device nodes and pinmux settings
  [DO NOT MERGE] ARM: dts: sun8i: a83t: bpi-m3: Enable PCM5122 codec
    with I2S1

 arch/arm/boot/dts/sun8i-a83t-bananapi-m3.dts |  33 +++++++++
 arch/arm/boot/dts/sun8i-a83t.dtsi            | 102 +++++++++++++++++++++++++++
 2 files changed, 135 insertions(+)

-- 
2.15.0

^ permalink raw reply

* [PATCH v2 1/3] ARM: dts: sun8i: a83t: Add I2S controller device nodes
From: Chen-Yu Tsai @ 2017-12-14  4:23 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20171214042350.29469-1-wens@csie.org>

The A83T has 3 I2S controllers. The first is multiplexed with the TDM
controller. The pins are generally connected to the codec side of the
AXP81x PMIC/codec/RTC chip. The second is free for other uses. The
third only supports output, and is connected internally to the HDMI
controller for HDMI audio output.

This patch adds device nodes for the controllers, and a default pinmux
setting for the second controller.

Signed-off-by: Chen-Yu Tsai <wens@csie.org>
Acked-by: Maxime Ripard <maxime.ripard@free-electrons.com>
---
 arch/arm/boot/dts/sun8i-a83t.dtsi | 47 +++++++++++++++++++++++++++++++++++++++
 1 file changed, 47 insertions(+)

diff --git a/arch/arm/boot/dts/sun8i-a83t.dtsi b/arch/arm/boot/dts/sun8i-a83t.dtsi
index a384b766f3dc..354cb4b48f47 100644
--- a/arch/arm/boot/dts/sun8i-a83t.dtsi
+++ b/arch/arm/boot/dts/sun8i-a83t.dtsi
@@ -348,6 +348,12 @@
 				drive-strength = <40>;
 			};
 
+			i2s1_pins: i2s1-pins {
+				/* I2S1 does not have external MCLK pin */
+				pins = "PG10", "PG11", "PG12", "PG13";
+				function = "i2s1";
+			};
+
 			mmc0_pins: mmc0-pins {
 				pins = "PF0", "PF1", "PF2",
 				       "PF3", "PF4", "PF5";
@@ -430,6 +436,47 @@
 			status = "disabled";
 		};
 
+		i2s0: i2s at 1c22000 {
+			#sound-dai-cells = <0>;
+			compatible = "allwinner,sun8i-a83t-i2s";
+			reg = <0x01c22000 0x400>;
+			interrupts = <GIC_SPI 13 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&ccu CLK_BUS_I2S0>, <&ccu CLK_I2S0>;
+			clock-names = "apb", "mod";
+			dmas = <&dma 3>, <&dma 3>;
+			resets = <&ccu RST_BUS_I2S0>;
+			dma-names = "rx", "tx";
+			status = "disabled";
+		};
+
+		i2s1: i2s at 1c22400 {
+			#sound-dai-cells = <0>;
+			compatible = "allwinner,sun8i-a83t-i2s";
+			reg = <0x01c22400 0x400>;
+			interrupts = <GIC_SPI 14 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&ccu CLK_BUS_I2S1>, <&ccu CLK_I2S1>;
+			clock-names = "apb", "mod";
+			dmas = <&dma 4>, <&dma 4>;
+			resets = <&ccu RST_BUS_I2S1>;
+			dma-names = "rx", "tx";
+			pinctrl-names = "default";
+			pinctrl-0 = <&i2s1_pins>;
+			status = "disabled";
+		};
+
+		i2s2: i2s at 1c22800 {
+			#sound-dai-cells = <0>;
+			compatible = "allwinner,sun8i-a83t-i2s";
+			reg = <0x01c22800 0x400>;
+			interrupts = <GIC_SPI 99 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&ccu CLK_BUS_I2S2>, <&ccu CLK_I2S2>;
+			clock-names = "apb", "mod";
+			dmas = <&dma 27>;
+			resets = <&ccu RST_BUS_I2S2>;
+			dma-names = "tx";
+			status = "disabled";
+		};
+
 		uart0: serial at 1c28000 {
 			compatible = "snps,dw-apb-uart";
 			reg = <0x01c28000 0x400>;
-- 
2.15.0

^ permalink raw reply related

* [PATCH v2 2/3] ARM: dts: sun8i: a83t: Add I2C device nodes and pinmux settings
From: Chen-Yu Tsai @ 2017-12-14  4:23 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20171214042350.29469-1-wens@csie.org>

The A83T has 3 I2C controllers under the standard bus. There is one
more in the R_ block section. The pin functions for the 3 controllers
are on PH 0~6. I2C2 can also be used on pins PE14 and PE15, but these
pins can also mux the CSI (camera sensor interface) controller's
embedded I2C controller. The latter seems to be preferred in the
reference designs for I2C camera sensor access, freeing I2C2 for other
uses.

This patch adds device nodes for the three standard I2C controllers,
as well as pinmux settings for the PH pins. For I2C0 and I2C1, since
they only have one possible setting, just set them by default.

Signed-off-by: Chen-Yu Tsai <wens@csie.org>
Acked-by: Maxime Ripard <maxime.ripard@free-electrons.com>
---
 arch/arm/boot/dts/sun8i-a83t.dtsi | 55 +++++++++++++++++++++++++++++++++++++++
 1 file changed, 55 insertions(+)

diff --git a/arch/arm/boot/dts/sun8i-a83t.dtsi b/arch/arm/boot/dts/sun8i-a83t.dtsi
index 354cb4b48f47..de5119a2a91c 100644
--- a/arch/arm/boot/dts/sun8i-a83t.dtsi
+++ b/arch/arm/boot/dts/sun8i-a83t.dtsi
@@ -348,6 +348,21 @@
 				drive-strength = <40>;
 			};
 
+			i2c0_pins: i2c0-pins {
+				pins = "PH0", "PH1";
+				function = "i2c0";
+			};
+
+			i2c1_pins: i2c1-pins {
+				pins = "PH2", "PH3";
+				function = "i2c1";
+			};
+
+			i2c2_ph_pins: i2c2-ph-pins {
+				pins = "PH4", "PH5";
+				function = "i2c2";
+			};
+
 			i2s1_pins: i2s1-pins {
 				/* I2S1 does not have external MCLK pin */
 				pins = "PG10", "PG11", "PG12", "PG13";
@@ -499,6 +514,46 @@
 			status = "disabled";
 		};
 
+		i2c0: i2c at 1c2ac00 {
+			compatible = "allwinner,sun8i-a83t-i2c",
+				     "allwinner,sun6i-a31-i2c";
+			reg = <0x01c2ac00 0x400>;
+			interrupts = <GIC_SPI 6 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&ccu CLK_BUS_I2C0>;
+			resets = <&ccu RST_BUS_I2C0>;
+			pinctrl-names = "default";
+			pinctrl-0 = <&i2c0_pins>;
+			status = "disabled";
+			#address-cells = <1>;
+			#size-cells = <0>;
+		};
+
+		i2c1: i2c at 1c2b000 {
+			compatible = "allwinner,sun8i-a83t-i2c",
+				     "allwinner,sun6i-a31-i2c";
+			reg = <0x01c2b000 0x400>;
+			interrupts = <GIC_SPI 7 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&ccu CLK_BUS_I2C1>;
+			resets = <&ccu RST_BUS_I2C1>;
+			pinctrl-names = "default";
+			pinctrl-0 = <&i2c1_pins>;
+			status = "disabled";
+			#address-cells = <1>;
+			#size-cells = <0>;
+		};
+
+		i2c2: i2c at 1c2b400 {
+			compatible = "allwinner,sun8i-a83t-i2c",
+				     "allwinner,sun6i-a31-i2c";
+			reg = <0x01c2b400 0x400>;
+			interrupts = <GIC_SPI 8 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&ccu CLK_BUS_I2C2>;
+			resets = <&ccu RST_BUS_I2C2>;
+			status = "disabled";
+			#address-cells = <1>;
+			#size-cells = <0>;
+		};
+
 		emac: ethernet at 1c30000 {
 			compatible = "allwinner,sun8i-a83t-emac";
 			syscon = <&syscon>;
-- 
2.15.0

^ permalink raw reply related

* [PATCH v2 3/3] [DO NOT MERGE] ARM: dts: sun8i: a83t: bpi-m3: Enable PCM5122 codec with I2S1
From: Chen-Yu Tsai @ 2017-12-14  4:23 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20171214042350.29469-1-wens@csie.org>

This patch enables a PiFi DAC+ V2.0, which is a PCM5122-based audio
output DAC add-on board for the Raspberry Pi B+ and later, connected
to the GPIO header of the Bananapi M3 via jumper cables. The power,
ground, and I2C pins are in the same position, but the I2S ones are
not.

The I2C controller used is I2C2, while the I2S controller is I2S1.

Signed-off-by: Chen-Yu Tsai <wens@csie.org>
---
 arch/arm/boot/dts/sun8i-a83t-bananapi-m3.dts | 33 ++++++++++++++++++++++++++++
 1 file changed, 33 insertions(+)

diff --git a/arch/arm/boot/dts/sun8i-a83t-bananapi-m3.dts b/arch/arm/boot/dts/sun8i-a83t-bananapi-m3.dts
index 6550bf0e594b..a9a208ebda12 100644
--- a/arch/arm/boot/dts/sun8i-a83t-bananapi-m3.dts
+++ b/arch/arm/boot/dts/sun8i-a83t-bananapi-m3.dts
@@ -70,6 +70,23 @@
 		gpio = <&pio 3 24 GPIO_ACTIVE_HIGH>; /* PD24 */
 	};
 
+	sound {
+		compatible = "simple-audio-card";
+		simple-audio-card,name = "PiFi DAC+ v2.0";
+		simple-audio-card,format = "i2s";
+		simple-audio-card,mclk-fs = <512>;
+		simple-audio-card,frame-master = <&link_cpu>;
+		simple-audio-card,bitclock-master = <&link_cpu>;
+
+		link_cpu: simple-audio-card,cpu {
+			sound-dai = <&i2s1>;
+		};
+
+		simple-audio-card,codec {
+			sound-dai = <&pcm5122>;
+		};
+	};
+
 	wifi_pwrseq: wifi_pwrseq {
 		compatible = "mmc-pwrseq-simple";
 		clocks = <&ac100_rtc 1>;
@@ -100,6 +117,22 @@
 	status = "okay";
 };
 
+&i2c2 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&i2c2_ph_pins>;
+	status = "okay";
+
+	pcm5122: pcm5122 at 4d {
+		#sound-dai-cells = <0>;
+		compatible = "ti,pcm5122";
+		reg = <0x4d>;
+	};
+};
+
+&i2s1 {
+	status = "okay";
+};
+
 &mdio {
 	rgmii_phy: ethernet-phy at 1 {
 		compatible = "ethernet-phy-ieee802.3-c22";
-- 
2.15.0

^ permalink raw reply related

* [PATCH 1/4] cpufreq: ti-cpufreq: Convert to module_platform_driver
From: Viresh Kumar @ 2017-12-14  4:29 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20171213203358.20839-2-d-gerlach@ti.com>

On 13-12-17, 14:33, Dave Gerlach wrote:
> ti-cpufreq will be responsible for calling dev_pm_opp_set_regulators on
> platforms that require AVS and ABB regulator support so we must be
> able to defer probe if regulators are not yet available, so change
> ti-cpufreq to be a module_platform_driver to allow for probe defer.
> 
> Signed-off-by: Dave Gerlach <d-gerlach@ti.com>
> ---
>  drivers/cpufreq/ti-cpufreq.c | 23 +++++++++++++++++++++--
>  1 file changed, 21 insertions(+), 2 deletions(-)
> 
> diff --git a/drivers/cpufreq/ti-cpufreq.c b/drivers/cpufreq/ti-cpufreq.c
> index 923317f03b4b..b1c230a1e2aa 100644
> --- a/drivers/cpufreq/ti-cpufreq.c
> +++ b/drivers/cpufreq/ti-cpufreq.c
> @@ -17,6 +17,7 @@
>  #include <linux/cpu.h>
>  #include <linux/io.h>
>  #include <linux/mfd/syscon.h>
> +#include <linux/module.h>
>  #include <linux/init.h>
>  #include <linux/of.h>
>  #include <linux/of_platform.h>
> @@ -195,7 +196,7 @@ static const struct of_device_id ti_cpufreq_of_match[] = {
>  	{},
>  };
>  
> -static int ti_cpufreq_init(void)
> +static int ti_cpufreq_probe(struct platform_device *pdev)
>  {
>  	u32 version[VERSION_COUNT];
>  	struct device_node *np;
> @@ -269,4 +270,22 @@ static int ti_cpufreq_init(void)
>  
>  	return ret;
>  }
> -device_initcall(ti_cpufreq_init);
> +
> +static int ti_cpufreq_init(void)
> +{
> +	platform_device_register_simple("ti-cpufreq", -1, NULL, 0);
> +	return 0;
> +}
> +module_init(ti_cpufreq_init);
> +
> +static struct platform_driver ti_cpufreq_driver = {
> +	.probe = ti_cpufreq_probe,
> +	.driver = {
> +		.name = "ti-cpufreq",
> +	},
> +};
> +module_platform_driver(ti_cpufreq_driver);
> +
> +MODULE_DESCRIPTION("TI CPUFreq/OPP hw-supported driver");
> +MODULE_AUTHOR("Dave Gerlach <d-gerlach@ti.com>");
> +MODULE_LICENSE("GPL v2");

Acked-by: Viresh Kumar <viresh.kumar@linaro.org>

-- 
viresh

^ permalink raw reply

* [PATCH 2/4] cpufreq: ti-cpufreq: Add support for multiple regulators
From: Viresh Kumar @ 2017-12-14  4:31 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20171213203358.20839-3-d-gerlach@ti.com>

On 13-12-17, 14:33, Dave Gerlach wrote:
> Some platforms, like those in the DRA7 and AM57 families, require the
> scaling of multiple regulators in order to properly support higher OPPs.
> Let the ti-cpufreq driver determine when this is required and pass the
> appropriate regulator names to the OPP core so that they can be properly
> managed.
> 
> Signed-off-by: Dave Gerlach <d-gerlach@ti.com>
> ---
>  drivers/cpufreq/ti-cpufreq.c | 28 ++++++++++++++++++++++++----
>  1 file changed, 24 insertions(+), 4 deletions(-)
> 
> diff --git a/drivers/cpufreq/ti-cpufreq.c b/drivers/cpufreq/ti-cpufreq.c
> index b1c230a1e2aa..a099b7bf74cd 100644
> --- a/drivers/cpufreq/ti-cpufreq.c
> +++ b/drivers/cpufreq/ti-cpufreq.c
> @@ -51,6 +51,7 @@ struct ti_cpufreq_soc_data {
>  	unsigned long efuse_mask;
>  	unsigned long efuse_shift;
>  	unsigned long rev_offset;
> +	bool multi_regulator;
>  };
>  
>  struct ti_cpufreq_data {
> @@ -58,6 +59,7 @@ struct ti_cpufreq_data {
>  	struct device_node *opp_node;
>  	struct regmap *syscon;
>  	const struct ti_cpufreq_soc_data *soc_data;
> +	struct opp_table *opp_table;
>  };
>  
>  static unsigned long amx3_efuse_xlate(struct ti_cpufreq_data *opp_data,
> @@ -96,6 +98,7 @@ static struct ti_cpufreq_soc_data am3x_soc_data = {
>  	.efuse_offset = 0x07fc,
>  	.efuse_mask = 0x1fff,
>  	.rev_offset = 0x600,
> +	.multi_regulator = false,
>  };
>  
>  static struct ti_cpufreq_soc_data am4x_soc_data = {
> @@ -104,6 +107,7 @@ static struct ti_cpufreq_soc_data am4x_soc_data = {
>  	.efuse_offset = 0x0610,
>  	.efuse_mask = 0x3f,
>  	.rev_offset = 0x600,
> +	.multi_regulator = false,
>  };
>  
>  static struct ti_cpufreq_soc_data dra7_soc_data = {
> @@ -112,6 +116,7 @@ static struct ti_cpufreq_soc_data dra7_soc_data = {
>  	.efuse_mask = 0xf80000,
>  	.efuse_shift = 19,
>  	.rev_offset = 0x204,
> +	.multi_regulator = true,
>  };
>  
>  /**
> @@ -201,7 +206,9 @@ static int ti_cpufreq_probe(struct platform_device *pdev)
>  	u32 version[VERSION_COUNT];
>  	struct device_node *np;
>  	const struct of_device_id *match;
> +	struct opp_table *ti_opp_table;
>  	struct ti_cpufreq_data *opp_data;
> +	const char * const reg_names[] = {"vdd", "vbb"};
>  	int ret;
>  
>  	np = of_find_node_by_path("/");
> @@ -248,16 +255,29 @@ static int ti_cpufreq_probe(struct platform_device *pdev)
>  	if (ret)
>  		goto fail_put_node;
>  
> -	ret = PTR_ERR_OR_ZERO(dev_pm_opp_set_supported_hw(opp_data->cpu_dev,
> -							  version, VERSION_COUNT));
> -	if (ret) {
> +	ti_opp_table = dev_pm_opp_set_supported_hw(opp_data->cpu_dev,
> +						   version, VERSION_COUNT);
> +	if (IS_ERR(ti_opp_table)) {
>  		dev_err(opp_data->cpu_dev,
>  			"Failed to set supported hardware\n");
> +		ret = PTR_ERR(ti_opp_table);
>  		goto fail_put_node;
>  	}
>  
> -	of_node_put(opp_data->opp_node);
> +	opp_data->opp_table = ti_opp_table;
> +
> +	if (opp_data->soc_data->multi_regulator) {
> +		ti_opp_table = dev_pm_opp_set_regulators(opp_data->cpu_dev,
> +							 reg_names,
> +							 ARRAY_SIZE(reg_names));
> +		if (IS_ERR(ti_opp_table)) {
> +			dev_pm_opp_put_supported_hw(opp_data->opp_table);
> +			ret =  PTR_ERR(ti_opp_table);
> +			goto fail_put_node;
> +		}
> +	}
>  
> +	of_node_put(opp_data->opp_node);
>  register_cpufreq_dt:
>  	platform_device_register_simple("cpufreq-dt", -1, NULL, 0);

Acked-by: Viresh Kumar <viresh.kumar@linaro.org>

-- 
viresh

^ permalink raw reply

* [PATCH 4/4] PM / OPP: Add ti-opp-supply driver
From: Viresh Kumar @ 2017-12-14  4:34 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20171213203358.20839-5-d-gerlach@ti.com>

On 13-12-17, 14:33, Dave Gerlach wrote:
> Introduce a ti-opp-supply driver that will use new multiple regulator
> support that is part of the OPP core This is needed on TI platforms like
> DRA7/AM57 in order to control both CPU regulator and Adaptive Body Bias
> (ABB) regulator. These regulators must be scaled in sequence during an
> OPP transition depending on whether or not the frequency is being scaled
> up or down.
> 
> This driver also implements AVS Class0 for these parts by looking up the
> required values from registers in the SoC and programming adjusted
> optimal voltage values for each OPP.
> 
> Signed-off-by: Dave Gerlach <d-gerlach@ti.com>
> ---
>  drivers/opp/Makefile        |   1 +
>  drivers/opp/ti-opp-supply.c | 428 ++++++++++++++++++++++++++++++++++++++++++++

Why is this added as a separate driver and not part of the same ti-cpufreq.c
file?

>  2 files changed, 429 insertions(+)
>  create mode 100644 drivers/opp/ti-opp-supply.c
> 
> diff --git a/drivers/opp/Makefile b/drivers/opp/Makefile
> index e70ceb406fe9..6ce6aefacc81 100644
> --- a/drivers/opp/Makefile
> +++ b/drivers/opp/Makefile
> @@ -2,3 +2,4 @@ ccflags-$(CONFIG_DEBUG_DRIVER)	:= -DDEBUG
>  obj-y				+= core.o cpu.o
>  obj-$(CONFIG_OF)		+= of.o
>  obj-$(CONFIG_DEBUG_FS)		+= debugfs.o
> +obj-$(CONFIG_ARM_TI_CPUFREQ)	+= ti-opp-supply.o
> diff --git a/drivers/opp/ti-opp-supply.c b/drivers/opp/ti-opp-supply.c
> new file mode 100644
> index 000000000000..73d795c90b79
> --- /dev/null
> +++ b/drivers/opp/ti-opp-supply.c
> @@ -0,0 +1,428 @@
> +/*
> + * Copyright (C) 2016-2017 Texas Instruments Incorporated - http://www.ti.com/
> + *	Nishanth Menon <nm@ti.com>
> + *	Dave Gerlach <d-gerlach@ti.com>
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License version 2 as
> + * published by the Free Software Foundation.

Please use the new SPDX format for licenses.

> + * TI OPP supply driver that provides override into the regulator control
> + * for generic opp core to handle devices with ABB regulator and/or
> + * SmartReflex Class0.
> + */
> +#include <linux/clk.h>
> +#include <linux/cpufreq.h>
> +#include <linux/device.h>
> +#include <linux/io.h>
> +#include <linux/module.h>
> +#include <linux/notifier.h>
> +#include <linux/of_device.h>
> +#include <linux/of.h>
> +#include <linux/platform_device.h>
> +#include <linux/pm_opp.h>
> +#include <linux/regulator/consumer.h>
> +#include <linux/slab.h>
> +
> +/**
> + * struct ti_opp_supply_optimum_voltage_table - optimized voltage table
> + * @reference_uv:	reference voltage (usually Nominal voltage)
> + * @optimized_uv:	Optimized voltage from efuse
> + */
> +struct ti_opp_supply_optimum_voltage_table {
> +	unsigned int reference_uv;
> +	unsigned int optimized_uv;
> +};
> +
> +/**
> + * struct ti_opp_supply_data - OMAP specific opp supply data
> + * @vdd_table:	Optimized voltage mapping table
> + * @num_vdd_table: number of entries in vdd_table
> + * @vdd_absolute_max_voltage_uv: absolute maximum voltage in UV for the supply
> + */
> +struct ti_opp_supply_data {
> +	struct ti_opp_supply_optimum_voltage_table *vdd_table;
> +	u32 num_vdd_table;
> +	u32 vdd_absolute_max_voltage_uv;
> +};
> +
> +static struct ti_opp_supply_data opp_data;
> +
> +/**
> + * struct ti_opp_supply_of_data - device tree match data
> + * @flags:	specific type of opp supply
> + * @efuse_voltage_mask: mask required for efuse register representing voltage
> + * @efuse_voltage_uv: Are the efuse entries in micro-volts? if not, assume
> + *		milli-volts.
> + */
> +struct ti_opp_supply_of_data {
> +#define OPPDM_EFUSE_CLASS0_OPTIMIZED_VOLTAGE	BIT(1)
> +#define OPPDM_HAS_NO_ABB			BIT(2)
> +	const u8 flags;
> +	const u32 efuse_voltage_mask;
> +	const bool efuse_voltage_uv;
> +};
> +
> +/**
> + * _store_optimized_voltages() - store optimized voltages
> + * @dev:	ti opp supply device for which we need to store info
> + * @data:	data specific to the device
> + *
> + * Picks up efuse based optimized voltages for VDD unique per device and
> + * stores it in internal data structure for use during transition requests.
> + *
> + * Return: If successful, 0, else appropriate error value.
> + */
> +static int _store_optimized_voltages(struct device *dev,
> +				     struct ti_opp_supply_data *data)
> +{
> +	void __iomem *base;
> +	struct property *prop;
> +	struct resource *res;
> +	const __be32 *val;
> +	int proplen, i;
> +	int ret = 0;
> +	struct ti_opp_supply_optimum_voltage_table *table;
> +	const struct ti_opp_supply_of_data *of_data = dev_get_drvdata(dev);
> +
> +	/* pick up Efuse based voltages */
> +	res = platform_get_resource(to_platform_device(dev), IORESOURCE_MEM, 0);
> +	if (!res) {
> +		dev_err(dev, "Unable to get IO resource\n");
> +		ret = -ENODEV;
> +		goto out_map;
> +	}
> +
> +	base = ioremap_nocache(res->start, resource_size(res));
> +	if (!base) {
> +		dev_err(dev, "Unable to map Efuse registers\n");
> +		ret = -ENOMEM;
> +		goto out_map;
> +	}
> +
> +	/* Fetch efuse-settings. */
> +	prop = of_find_property(dev->of_node, "ti,efuse-settings", NULL);
> +	if (!prop) {
> +		dev_err(dev, "No 'ti,efuse-settings' property found\n");
> +		ret = -EINVAL;
> +		goto out;
> +	}
> +
> +	proplen = prop->length / sizeof(int);
> +	data->num_vdd_table = proplen / 2;
> +	/* Verify for corrupted OPP entries in dt */
> +	if (data->num_vdd_table * 2 * sizeof(int) != prop->length) {
> +		dev_err(dev, "Invalid 'ti,efuse-settings'\n");
> +		ret = -EINVAL;
> +		goto out;
> +	}
> +
> +	ret = of_property_read_u32(dev->of_node, "ti,absolute-max-voltage-uv",
> +				   &data->vdd_absolute_max_voltage_uv);
> +	if (ret) {
> +		dev_err(dev, "ti,absolute-max-voltage-uv is missing\n");
> +		ret = -EINVAL;
> +		goto out;
> +	}
> +
> +	table = kzalloc(sizeof(*data->vdd_table) *
> +				  data->num_vdd_table, GFP_KERNEL);
> +	if (!table) {
> +		ret = -ENOMEM;
> +		goto out;
> +	}
> +	data->vdd_table = table;
> +
> +	val = prop->value;
> +	for (i = 0; i < data->num_vdd_table; i++, table++) {
> +		u32 efuse_offset;
> +		u32 tmp;
> +
> +		table->reference_uv = be32_to_cpup(val++);
> +		efuse_offset = be32_to_cpup(val++);
> +
> +		tmp = readl(base + efuse_offset);
> +		tmp &= of_data->efuse_voltage_mask;
> +		tmp >>= __ffs(of_data->efuse_voltage_mask);
> +
> +		table->optimized_uv = of_data->efuse_voltage_uv ? tmp :
> +					tmp * 1000;
> +
> +		dev_dbg(dev, "[%d] efuse=0x%08x volt_table=%d vset=%d\n",
> +			i, efuse_offset, table->reference_uv,
> +			table->optimized_uv);
> +
> +		/*
> +		 * Some older samples might not have optimized efuse
> +		 * Use reference voltage for those - just add debug message
> +		 * for them.
> +		 */
> +		if (!table->optimized_uv) {
> +			dev_dbg(dev, "[%d] efuse=0x%08x volt_table=%d:vset0\n",
> +				i, efuse_offset, table->reference_uv);
> +			table->optimized_uv = table->reference_uv;
> +		}
> +	}
> +out:
> +	iounmap(base);
> +out_map:
> +	return ret;
> +}
> +
> +/**
> + * _free_optimized_voltages() - free resources for optvoltages
> + * @dev:	device for which we need to free info
> + * @data:	data specific to the device
> + */
> +static void _free_optimized_voltages(struct device *dev,
> +				     struct ti_opp_supply_data *data)
> +{
> +	kfree(data->vdd_table);
> +	data->vdd_table = NULL;
> +	data->num_vdd_table = 0;
> +}
> +
> +/**
> + * _get_optimal_vdd_voltage() - Finds optimal voltage for the supply
> + * @dev:	device for which we need to find info
> + * @data:	data specific to the device
> + * @reference_uv:	reference voltage (OPP voltage) for which we need value
> + *
> + * Return: if a match is found, return optimized voltage, else return
> + * reference_uv, also return reference_uv if no optimization is needed.
> + */
> +static int _get_optimal_vdd_voltage(struct device *dev,
> +				    struct ti_opp_supply_data *data,
> +				    int reference_uv)
> +{
> +	int i;
> +	struct ti_opp_supply_optimum_voltage_table *table;
> +
> +	if (!data->num_vdd_table)
> +		return reference_uv;
> +
> +	table = data->vdd_table;
> +	if (!table)
> +		return -EINVAL;
> +
> +	/* Find a exact match - this list is usually very small */
> +	for (i = 0; i < data->num_vdd_table; i++, table++)
> +		if (table->reference_uv == reference_uv)
> +			return table->optimized_uv;
> +
> +	/* IF things are screwed up, we'd make a mess on console.. ratelimit */
> +	dev_err_ratelimited(dev, "%s: Failed optimized voltage match for %d\n",
> +			    __func__, reference_uv);
> +	return reference_uv;
> +}
> +
> +static int _opp_set_voltage(struct device *dev,
> +			    struct dev_pm_opp_supply *supply,
> +			    int new_target_uv, struct regulator *reg,
> +			    char *reg_name)
> +{
> +	int ret;
> +	unsigned long vdd_uv, uv_max;
> +
> +	if (new_target_uv)
> +		vdd_uv = new_target_uv;
> +	else
> +		vdd_uv = supply->u_volt;
> +
> +	/*
> +	 * If we do have an absolute max voltage specified, then we should
> +	 * use that voltage instead to allow for cases where the voltage rails
> +	 * are ganged (example if we set the max for an opp as 1.12v, and
> +	 * the absolute max is 1.5v, for another rail to get 1.25v, it cannot
> +	 * be achieved if the regulator is constrainted to max of 1.12v, even
> +	 * if it can function at 1.25v
> +	 */
> +	if (opp_data.vdd_absolute_max_voltage_uv)
> +		uv_max = opp_data.vdd_absolute_max_voltage_uv;
> +	else
> +		uv_max = supply->u_volt_max;
> +
> +	if (vdd_uv > uv_max ||
> +	    vdd_uv < supply->u_volt_min ||
> +	    supply->u_volt_min > uv_max) {
> +		dev_warn(dev,
> +			 "Invalid range voltages [Min:%lu target:%lu Max:%lu]\n",
> +			 supply->u_volt_min, vdd_uv, uv_max);
> +		return -EINVAL;
> +	}
> +
> +	dev_dbg(dev, "%s scaling to %luuV[min %luuV max %luuV]\n", reg_name,
> +		vdd_uv, supply->u_volt_min,
> +		uv_max);
> +
> +	ret = regulator_set_voltage_triplet(reg,
> +					    supply->u_volt_min,
> +					    vdd_uv,
> +					    uv_max);
> +	if (ret) {
> +		dev_err(dev, "%s failed for %luuV[min %luuV max %luuV]\n",
> +			reg_name, vdd_uv, supply->u_volt_min,
> +			uv_max);
> +		return ret;
> +	}
> +
> +	return 0;
> +}
> +
> +/**
> + * ti_opp_supply_set_opp() - do the opp supply transition
> + * @data:	information on regulators and new and old opps provided by
> + *		opp core to use in transition
> + *
> + * Return: If successful, 0, else appropriate error value.
> + */
> +int ti_opp_supply_set_opp(struct dev_pm_set_opp_data *data)
> +{
> +	struct dev_pm_opp_supply *old_supply_vdd = &data->old_opp.supplies[0];
> +	struct dev_pm_opp_supply *old_supply_vbb = &data->old_opp.supplies[1];
> +	struct dev_pm_opp_supply *new_supply_vdd = &data->new_opp.supplies[0];
> +	struct dev_pm_opp_supply *new_supply_vbb = &data->new_opp.supplies[1];
> +	struct device *dev = data->dev;
> +	unsigned long old_freq = data->old_opp.rate, freq = data->new_opp.rate;
> +	struct clk *clk = data->clk;
> +	struct regulator *vdd_reg = data->regulators[0];
> +	struct regulator *vbb_reg = data->regulators[1];
> +	int vdd_uv;
> +	int ret;
> +
> +	vdd_uv = _get_optimal_vdd_voltage(dev, &opp_data,
> +					  new_supply_vbb->u_volt);
> +
> +	/* Scaling up? Scale voltage before frequency */
> +	if (freq > old_freq) {
> +		ret = _opp_set_voltage(dev, new_supply_vdd, vdd_uv, vdd_reg,
> +				       "vdd");
> +		if (ret)
> +			goto restore_voltage;
> +
> +		ret = _opp_set_voltage(dev, new_supply_vbb, 0, vbb_reg, "vbb");
> +		if (ret)
> +			goto restore_voltage;
> +	}
> +
> +	/* Change frequency */
> +	dev_dbg(dev, "%s: switching OPP: %lu Hz --> %lu Hz\n",
> +		__func__, old_freq, freq);
> +
> +	ret = clk_set_rate(clk, freq);
> +	if (ret) {
> +		dev_err(dev, "%s: failed to set clock rate: %d\n", __func__,
> +			ret);
> +		goto restore_voltage;
> +	}
> +
> +	/* Scaling down? Scale voltage after frequency */
> +	if (freq < old_freq) {
> +		ret = _opp_set_voltage(dev, new_supply_vbb, 0, vbb_reg, "vbb");
> +		if (ret)
> +			goto restore_freq;
> +
> +		ret = _opp_set_voltage(dev, new_supply_vdd, vdd_uv, vdd_reg,
> +				       "vdd");
> +		if (ret)
> +			goto restore_freq;
> +	}
> +
> +	return 0;
> +
> +restore_freq:
> +	ret = clk_set_rate(clk, old_freq);
> +	if (ret)
> +		dev_err(dev, "%s: failed to restore old-freq (%lu Hz)\n",
> +			__func__, old_freq);
> +restore_voltage:
> +	/* This shouldn't harm even if the voltages weren't updated earlier */
> +	if (old_supply_vdd->u_volt) {
> +		ret = _opp_set_voltage(dev, old_supply_vbb, 0, vbb_reg, "vbb");
> +		if (ret)
> +			return ret;
> +
> +		ret = _opp_set_voltage(dev, old_supply_vdd, 0, vdd_reg,
> +				       "vdd");
> +		if (ret)
> +			return ret;
> +	}
> +
> +	return ret;
> +}
> +
> +static const struct ti_opp_supply_of_data omap_generic_of_data = {
> +};
> +
> +static const struct ti_opp_supply_of_data omap_omap5_of_data = {
> +	.flags = OPPDM_EFUSE_CLASS0_OPTIMIZED_VOLTAGE,
> +	.efuse_voltage_mask = 0xFFF,
> +	.efuse_voltage_uv = false,
> +};
> +
> +static const struct ti_opp_supply_of_data omap_omap5core_of_data = {
> +	.flags = OPPDM_EFUSE_CLASS0_OPTIMIZED_VOLTAGE | OPPDM_HAS_NO_ABB,
> +	.efuse_voltage_mask = 0xFFF,
> +	.efuse_voltage_uv = false,
> +};
> +
> +static const struct of_device_id ti_opp_supply_of_match[] = {
> +	{.compatible = "ti,omap-opp-supply", .data = &omap_generic_of_data},
> +	{.compatible = "ti,omap5-opp-supply", .data = &omap_omap5_of_data},
> +	{.compatible = "ti,omap5-core-opp-supply",
> +	 .data = &omap_omap5core_of_data},
> +	{},
> +};
> +MODULE_DEVICE_TABLE(of, ti_opp_supply_of_match);
> +
> +static int ti_opp_supply_probe(struct platform_device *pdev)
> +{
> +	struct device *dev = &pdev->dev;
> +	struct device *cpu_dev = get_cpu_device(0);
> +	const struct of_device_id *match;
> +	const struct ti_opp_supply_of_data *of_data;
> +	int ret = 0;
> +
> +	match = of_match_device(ti_opp_supply_of_match, dev);
> +	if (!match) {
> +		/* We do not expect this to happen */
> +		dev_err(dev, "%s: Unable to match device\n", __func__);
> +		return -ENODEV;
> +	}
> +	if (!match->data) {
> +		/* Again, unlikely.. but mistakes do happen */
> +		dev_err(dev, "%s: Bad data in match\n", __func__);
> +		return -EINVAL;
> +	}
> +	of_data = match->data;
> +
> +	dev_set_drvdata(dev, (void *)of_data);
> +
> +	/* If we need optimized voltage */
> +	if (of_data->flags & OPPDM_EFUSE_CLASS0_OPTIMIZED_VOLTAGE) {
> +		ret = _store_optimized_voltages(dev, &opp_data);
> +		if (ret)
> +			return ret;
> +	}
> +
> +	ret = PTR_ERR_OR_ZERO(dev_pm_opp_register_set_opp_helper(cpu_dev,
> +								 ti_opp_supply_set_opp));
> +	if (ret)
> +		_free_optimized_voltages(dev, &opp_data);
> +
> +	return ret;
> +}
> +
> +static struct platform_driver ti_opp_supply_driver = {
> +	.probe = ti_opp_supply_probe,
> +	.driver = {
> +		   .name = "ti_opp_supply",
> +		   .owner = THIS_MODULE,
> +		   .of_match_table = of_match_ptr(ti_opp_supply_of_match),
> +		   },
> +};
> +module_platform_driver(ti_opp_supply_driver);
> +
> +MODULE_DESCRIPTION("Texas Instruments OMAP OPP Supply driver");
> +MODULE_AUTHOR("Texas Instruments Inc.");
> +MODULE_LICENSE("GPL v2");

Looks fine otherwise.

-- 
viresh

^ permalink raw reply

* [PATCH] KVM: arm/arm64: don't set vtimer->cnt_ctl in kvm_arch_timer_handler
From: Jia He @ 2017-12-14  4:57 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20171213091803.GQ910@cbox>

Hi Christoffer

I have tried your newer level-mapped-v7 branch, but bug is still there.

There is no special load in both host and guest. The guest (kernel 4.14) 
is often hanging when booting

the guest kernel log

[ OK ] Reached target Remote File Systems.
Starting File System Check on /dev/mapper/fedora-root...
[ OK ] Started File System Check on /dev/mapper/fedora-root.
Mounting /sysroot...
[ 2.670764] SGI XFS with ACLs, security attributes, no debug enabled
[ 2.678180] XFS (dm-0): Mounting V5 Filesystem
[ 2.740364] XFS (dm-0): Ending clean mount
[ OK ] Mounted /sysroot.
[ OK ] Reached target Initrd Root File System.
Starting Reload Configuration from the Real Root...
[ 61.288215] INFO: rcu_sched detected stalls on CPUs/tasks:
[ 61.290791] 1-...!: (0 ticks this GP) idle=574/0/0 softirq=5/5 fqs=1
[ 61.293664] (detected by 0, t=6002 jiffies, g=-263, c=-264, q=39760)
[ 61.296480] Task dump for CPU 1:
[ 61.297938] swapper/1 R running task 0 0 1 0x00000020
[ 61.300643] Call trace:
[ 61.301260] __switch_to+0x6c/0x78
[ 61.302095] cpu_number+0x0/0x8
[ 61.302867] rcu_sched kthread starved for 6000 jiffies! 
g18446744073709551353 c18446744073709551352 f0x0 RCU_GP_WAIT_FQS(3) 
->state=0x402 ->cpu=1
[ 61.305941] rcu_sched I 0 8 2 0x00000020
[ 61.307250] Call trace:
[ 61.307854] __switch_to+0x6c/0x78
[ 61.308693] __schedule+0x268/0x8f0
[ 61.309545] schedule+0x2c/0x88
[ 61.310325] schedule_timeout+0x84/0x3b8
[ 61.311278] rcu_gp_kthread+0x4d4/0x7d8
[ 61.312213] kthread+0x134/0x138
[ 61.313001] ret_from_fork+0x10/0x1c

Maybe my previous patch is not perfect enough, thanks for your comments.

I digged it futher more, do you think below code logic is possibly 
problematic?


vtimer_save_state?????????? (vtimer->loaded = false, cntv_ctl is 0)

kvm_arch_timer_handler????????(read cntv_ctl and set vtimer->cnt_ctl = 0)

vtimer_restore_state ? ? ? ? ?? (write vtimer->cnt_ctl to cntv_ctl, then 
cntv_ctl will

 ??? ??? ??? ??? ?? ? ? be 0 forever)


If above analysis is reasonable, how about below patch? already tested 
in my arm64 server.

diff --git a/virt/kvm/arm/arch_timer.c b/virt/kvm/arm/arch_timer.c
index f9555b1..ee6dd3f 100644
--- a/virt/kvm/arm/arch_timer.c
+++ b/virt/kvm/arm/arch_timer.c
@@ -99,7 +99,7 @@ static irqreturn_t kvm_arch_timer_handler(int irq, 
void *dev_id)
 ??????? }
 ??????? vtimer = vcpu_vtimer(vcpu);

-?????? if (!vtimer->irq.level) {
+?????? if (vtimer->loaded && !vtimer->irq.level) {
 ??????????????? vtimer->cnt_ctl = read_sysreg_el0(cntv_ctl);
 ??????????????? if (kvm_timer_irq_can_fire(vtimer))
 ??????????????????????? kvm_timer_update_irq(vcpu, true, vtimer);

Cheers,

Jia



On 12/13/2017 5:18 PM, Christoffer Dall Wrote:
> On Tue, Dec 12, 2017 at 11:00:07PM -0800, Jia He wrote:
>> In our Armv8a server (qualcomm Amberwing, non VHE), after applying
>> Christoffer's timer optimizing patchset(Optimize arch timer register
>> handling), the guest is hang during kernel booting.
>>
>> The error root cause might be as follows:
>> 1. in kvm_arch_timer_handler, it reset vtimer->cnt_ctl with current
>> cntv_ctl register value. And then it missed some cases to update timer's
>> irq (irq.level) when kvm_timer_irq_can_fire() is false
> Why should it set the irq level to true when the timer cannot fire?
>
>> 2. It causes kvm_vcpu_check_block return 0 instead of -EINTR
>> 	kvm_vcpu_check_block
>> 		kvm_cpu_has_pending_timer
>> 			kvm_timer_is_pending
>> 				kvm_timer_should_fire
>> 3. Thus, the kvm hyp code can not break the loop in kvm_vcpu_block (halt
>> poll process) and the guest is hang forever
> This is just a polling loop which will expire after some time, so it
> shouldn't halt the guest indefinitely, but merely slow it down for some
> while, if we have a bug.  Is that the behavior you're seeing or are you
> seeing the guest coming to a complete halt?
>
>> Fixes: b103cc3f10c0 ("KVM: arm/arm64: Avoid timer save/restore in vcpu entry/exit")
>> Signed-off-by: Jia He <jia.he@hxt-semitech.com>
>> ---
>>   virt/kvm/arm/arch_timer.c | 1 -
>>   1 file changed, 1 deletion(-)
>>
>> diff --git a/virt/kvm/arm/arch_timer.c b/virt/kvm/arm/arch_timer.c
>> index f9555b1..bb86433 100644
>> --- a/virt/kvm/arm/arch_timer.c
>> +++ b/virt/kvm/arm/arch_timer.c
>> @@ -100,7 +100,6 @@ static irqreturn_t kvm_arch_timer_handler(int irq, void *dev_id)
>>   	vtimer = vcpu_vtimer(vcpu);
>>   
>>   	if (!vtimer->irq.level) {
>> -		vtimer->cnt_ctl = read_sysreg_el0(cntv_ctl);
> This fix is clearly not correct, as it would prevent forwarding timer
> interrupts in some cases.
>
>>   		if (kvm_timer_irq_can_fire(vtimer))
>>   			kvm_timer_update_irq(vcpu, true, vtimer);
>>   	}
>> -- 
>> 2.7.4
>>
> I actually don't see how the above scenario you painted can happen.
>
> If you're in the polling loop, that means that the timer state is loaded
> on the vcpu, and that means you can take interrupts from the timer, and
> when you take interrupts, you will set the irq.level.
>
> And here's the first bit of logic in kvm_timer_is_pending():
>
> 	if (vtimer->irq.level || ptimer->irq.level)
> 		return true;
>
> So that would break the loop.
>
> I'm not able to reproduce on my side with a non-VHE platform.
>
> What is the workload you're running to reproduce this, and what is the
> exact kernel tree and kernel configuration you're using?
>
> Thanks,
> -Christoffer
>
>
>

^ permalink raw reply related

* [RFC PATCH 5/5] ARM: NOMMU: Support PMSAv8 MPU
From: afzal mohammed @ 2017-12-14  5:01 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1513184527-44120-6-git-send-email-vladimir.murzin@arm.com>

Hi,

On Wed, Dec 13, 2017 at 05:02:07PM +0000, Vladimir Murzin wrote:

> ARMv8R/M architecture defines new memory protection scheme - PMSAv8

Is there a public ARMv8-R architecture reference manual available ?,
seems only ARMv8-A and ARMv8-M ARM's are publically available.

afzal

^ permalink raw reply

* [PATCH V4 09/12] boot_constraint: Add earlycon helper
From: Viresh Kumar @ 2017-12-14  5:22 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20171213094450.GD13194@kroah.com>

On 13-12-17, 10:44, Greg Kroah-Hartman wrote:
> And this feels really odd, does it really save any work for the
> individual "constraint" to check for this option?  I'm all for helper
> functions, but this feels like more work than it's worth...

Ok, will move this code to individual platform driver files for now.

-- 
viresh

^ permalink raw reply

* [PATCH] KVM: arm/arm64: don't set vtimer->cnt_ctl in kvm_arch_timer_handler
From: Jia He @ 2017-12-14  5:35 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <dc95b58c-ee6c-e5c7-1f37-8f69c789a1fc@gmail.com>

Hi


On 12/14/2017 12:57 PM, Jia He Wrote:
> Hi Christoffer
>
> I have tried your newer level-mapped-v7 branch, but bug is still there.
>
> There is no special load in both host and guest. The guest (kernel 
> 4.14) is often hanging when booting
>
> the guest kernel log
>
> [ OK ] Reached target Remote File Systems.
> Starting File System Check on /dev/mapper/fedora-root...
> [ OK ] Started File System Check on /dev/mapper/fedora-root.
> Mounting /sysroot...
> [ 2.670764] SGI XFS with ACLs, security attributes, no debug enabled
> [ 2.678180] XFS (dm-0): Mounting V5 Filesystem
> [ 2.740364] XFS (dm-0): Ending clean mount
> [ OK ] Mounted /sysroot.
> [ OK ] Reached target Initrd Root File System.
> Starting Reload Configuration from the Real Root...
> [ 61.288215] INFO: rcu_sched detected stalls on CPUs/tasks:
> [ 61.290791] 1-...!: (0 ticks this GP) idle=574/0/0 softirq=5/5 fqs=1
> [ 61.293664] (detected by 0, t=6002 jiffies, g=-263, c=-264, q=39760)
> [ 61.296480] Task dump for CPU 1:
> [ 61.297938] swapper/1 R running task 0 0 1 0x00000020
> [ 61.300643] Call trace:
> [ 61.301260] __switch_to+0x6c/0x78
> [ 61.302095] cpu_number+0x0/0x8
> [ 61.302867] rcu_sched kthread starved for 6000 jiffies! 
> g18446744073709551353 c18446744073709551352 f0x0 RCU_GP_WAIT_FQS(3) 
> ->state=0x402 ->cpu=1
> [ 61.305941] rcu_sched I 0 8 2 0x00000020
> [ 61.307250] Call trace:
> [ 61.307854] __switch_to+0x6c/0x78
> [ 61.308693] __schedule+0x268/0x8f0
> [ 61.309545] schedule+0x2c/0x88
> [ 61.310325] schedule_timeout+0x84/0x3b8
> [ 61.311278] rcu_gp_kthread+0x4d4/0x7d8
> [ 61.312213] kthread+0x134/0x138
> [ 61.313001] ret_from_fork+0x10/0x1c
>
> Maybe my previous patch is not perfect enough, thanks for your comments.
>
> I digged it futher more, do you think below code logic is possibly 
> problematic?
>
>
> vtimer_save_state?????????? (vtimer->loaded = false, cntv_ctl is 0)
>
> kvm_arch_timer_handler????????(read cntv_ctl and set vtimer->cnt_ctl = 0)
>
> vtimer_restore_state ? ? ? ? ?? (write vtimer->cnt_ctl to cntv_ctl, 
> then cntv_ctl will
>
> ??? ??? ??? ??? ?? ? ? be 0 forever)
sorry, adjust the format, make it easy for reading:

vtimer_save_state?????????????????? (vtimer->loaded = false, cntv_ctl is 0)
kvm_arch_timer_handler????????(read cntv_ctl and set vtimer->cnt_ctl = 0)
vtimer_restore_state ? ? ? ? ???? (write vtimer->cnt_ctl to cntv_ctl, 
then cntv_ctl will be 0 forever)

-- 
Cheers,
Jia

>
>
> If above analysis is reasonable, how about below patch? already tested 
> in my arm64 server.
>
> diff --git a/virt/kvm/arm/arch_timer.c b/virt/kvm/arm/arch_timer.c
> index f9555b1..ee6dd3f 100644
> --- a/virt/kvm/arm/arch_timer.c
> +++ b/virt/kvm/arm/arch_timer.c
> @@ -99,7 +99,7 @@ static irqreturn_t kvm_arch_timer_handler(int irq, 
> void *dev_id)
> ??????? }
> ??????? vtimer = vcpu_vtimer(vcpu);
>
> -?????? if (!vtimer->irq.level) {
> +?????? if (vtimer->loaded && !vtimer->irq.level) {
> ??????????????? vtimer->cnt_ctl = read_sysreg_el0(cntv_ctl);
> ??????????????? if (kvm_timer_irq_can_fire(vtimer))
> ??????????????????????? kvm_timer_update_irq(vcpu, true, vtimer);
>
> Cheers,
>
> Jia
>
>
>
> On 12/13/2017 5:18 PM, Christoffer Dall Wrote:
>> On Tue, Dec 12, 2017 at 11:00:07PM -0800, Jia He wrote:
>>> In our Armv8a server (qualcomm Amberwing, non VHE), after applying
>>> Christoffer's timer optimizing patchset(Optimize arch timer register
>>> handling), the guest is hang during kernel booting.
>>>
>>> The error root cause might be as follows:
>>> 1. in kvm_arch_timer_handler, it reset vtimer->cnt_ctl with current
>>> cntv_ctl register value. And then it missed some cases to update 
>>> timer's
>>> irq (irq.level) when kvm_timer_irq_can_fire() is false
>> Why should it set the irq level to true when the timer cannot fire?
>>
>>> 2. It causes kvm_vcpu_check_block return 0 instead of -EINTR
>>> ????kvm_vcpu_check_block
>>> ??????? kvm_cpu_has_pending_timer
>>> ??????????? kvm_timer_is_pending
>>> ??????????????? kvm_timer_should_fire
>>> 3. Thus, the kvm hyp code can not break the loop in kvm_vcpu_block 
>>> (halt
>>> poll process) and the guest is hang forever
>> This is just a polling loop which will expire after some time, so it
>> shouldn't halt the guest indefinitely, but merely slow it down for some
>> while, if we have a bug.? Is that the behavior you're seeing or are you
>> seeing the guest coming to a complete halt?
>>
>>> Fixes: b103cc3f10c0 ("KVM: arm/arm64: Avoid timer save/restore in 
>>> vcpu entry/exit")
>>> Signed-off-by: Jia He <jia.he@hxt-semitech.com>
>>> ---
>>> ? virt/kvm/arm/arch_timer.c | 1 -
>>> ? 1 file changed, 1 deletion(-)
>>>
>>> diff --git a/virt/kvm/arm/arch_timer.c b/virt/kvm/arm/arch_timer.c
>>> index f9555b1..bb86433 100644
>>> --- a/virt/kvm/arm/arch_timer.c
>>> +++ b/virt/kvm/arm/arch_timer.c
>>> @@ -100,7 +100,6 @@ static irqreturn_t kvm_arch_timer_handler(int 
>>> irq, void *dev_id)
>>> ????? vtimer = vcpu_vtimer(vcpu);
>>> ? ????? if (!vtimer->irq.level) {
>>> -??????? vtimer->cnt_ctl = read_sysreg_el0(cntv_ctl);
>> This fix is clearly not correct, as it would prevent forwarding timer
>> interrupts in some cases.
>>
>>> ????????? if (kvm_timer_irq_can_fire(vtimer))
>>> ????????????? kvm_timer_update_irq(vcpu, true, vtimer);
>>> ????? }
>>> -- 
>>> 2.7.4
>>>
>> I actually don't see how the above scenario you painted can happen.
>>
>> If you're in the polling loop, that means that the timer state is loaded
>> on the vcpu, and that means you can take interrupts from the timer, and
>> when you take interrupts, you will set the irq.level.
>>
>> And here's the first bit of logic in kvm_timer_is_pending():
>>
>> ????if (vtimer->irq.level || ptimer->irq.level)
>> ??????? return true;
>>
>> So that would break the loop.
>>
>> I'm not able to reproduce on my side with a non-VHE platform.
>>
>> What is the workload you're running to reproduce this, and what is the
>> exact kernel tree and kernel configuration you're using?
>>
>> Thanks,
>> -Christoffer
>>
>>
>>

^ permalink raw reply

* [xlnx:master 1118/1121] drivers/gpu/drm/xilinx/xilinx_drm_drv.c:401:24: warning: format '%lu' expects argument of type 'long unsigned int', but argument 3 has type 'unsigned int'
From: kbuild test robot @ 2017-12-14  6:08 UTC (permalink / raw)
  To: linux-arm-kernel

tree:   https://github.com/Xilinx/linux-xlnx master
head:   9c2e29b2c81dbb1efb7ee4944b18e12226b97513
commit: ea3243d34738a7900ce247f812a16405fc25d0ef [1118/1121] drm: xilinx: drv: Update dma mask accordingly
config: i386-allmodconfig (attached as .config)
compiler: gcc-7 (Debian 7.2.0-12) 7.2.1 20171025
reproduce:
        git checkout ea3243d34738a7900ce247f812a16405fc25d0ef
        # save the attached .config to linux build tree
        make ARCH=i386 

All warnings (new ones prefixed by >>):

   In file included from include/linux/dma-mapping.h:6:0,
                    from include/drm/drmP.h:37,
                    from drivers/gpu/drm/xilinx/xilinx_drm_drv.c:18:
   drivers/gpu/drm/xilinx/xilinx_drm_drv.c: In function 'xilinx_drm_load':
>> drivers/gpu/drm/xilinx/xilinx_drm_drv.c:401:24: warning: format '%lu' expects argument of type 'long unsigned int', but argument 3 has type 'unsigned int' [-Wformat=]
      dev_info(&pdev->dev, "failed to set coherent mask (%lu)\n",
                           ^
   include/linux/device.h:1195:51: note: in definition of macro 'dev_info'
    #define dev_info(dev, fmt, arg...) _dev_info(dev, fmt, ##arg)
                                                      ^~~

vim +401 drivers/gpu/drm/xilinx/xilinx_drm_drv.c

   288	
   289	/* load xilinx drm */
   290	static int xilinx_drm_load(struct drm_device *drm, unsigned long flags)
   291	{
   292		struct xilinx_drm_private *private;
   293		struct drm_encoder *encoder;
   294		struct drm_connector *connector;
   295		struct device_node *encoder_node, *ep = NULL, *remote;
   296		struct platform_device *pdev = drm->platformdev;
   297		struct component_match *match = NULL;
   298		unsigned int align, depth, i = 0;
   299		int bpp, ret;
   300	
   301		private = devm_kzalloc(drm->dev, sizeof(*private), GFP_KERNEL);
   302		if (!private)
   303			return -ENOMEM;
   304	
   305		drm_mode_config_init(drm);
   306	
   307		/* create a xilinx crtc */
   308		private->crtc = xilinx_drm_crtc_create(drm);
   309		if (IS_ERR(private->crtc)) {
   310			DRM_DEBUG_DRIVER("failed to create xilinx crtc\n");
   311			ret = PTR_ERR(private->crtc);
   312			goto err_out;
   313		}
   314	
   315		while ((encoder_node = of_parse_phandle(drm->dev->of_node,
   316							"xlnx,encoder-slave", i))) {
   317			encoder = xilinx_drm_encoder_create(drm, encoder_node);
   318			of_node_put(encoder_node);
   319			if (IS_ERR(encoder)) {
   320				DRM_DEBUG_DRIVER("failed to create xilinx encoder\n");
   321				ret = PTR_ERR(encoder);
   322				goto err_out;
   323			}
   324	
   325			connector = xilinx_drm_connector_create(drm, encoder, i);
   326			if (IS_ERR(connector)) {
   327				DRM_DEBUG_DRIVER("failed to create xilinx connector\n");
   328				ret = PTR_ERR(connector);
   329				goto err_out;
   330			}
   331	
   332			i++;
   333		}
   334	
   335		while (1) {
   336			ep = of_graph_get_next_endpoint(drm->dev->of_node, ep);
   337			if (!ep)
   338				break;
   339	
   340			of_node_put(ep);
   341			remote = of_graph_get_remote_port_parent(ep);
   342			if (!remote || !of_device_is_available(remote)) {
   343				of_node_put(remote);
   344				continue;
   345			}
   346	
   347			component_match_add(drm->dev, &match, compare_of, remote);
   348			of_node_put(remote);
   349			i++;
   350		}
   351	
   352		if (i == 0) {
   353			DRM_ERROR("failed to get an encoder slave node\n");
   354			return -ENODEV;
   355		}
   356	
   357		ret = drm_vblank_init(drm, 1);
   358		if (ret) {
   359			dev_err(&pdev->dev, "failed to initialize vblank\n");
   360			goto err_master;
   361		}
   362	
   363		/* enable irq to enable vblank feature */
   364		drm->irq_enabled = 1;
   365	
   366		drm->dev_private = private;
   367		private->drm = drm;
   368		xilinx_drm_mode_config_init(drm);
   369	
   370		/* initialize xilinx framebuffer */
   371		drm_fb_get_bpp_depth(xilinx_drm_crtc_get_format(private->crtc),
   372				     &depth, &bpp);
   373		if (bpp) {
   374			align = xilinx_drm_crtc_get_align(private->crtc);
   375			private->fb = xilinx_drm_fb_init(drm, bpp, 1, 1, align,
   376							 xilinx_drm_fbdev_vres);
   377			if (IS_ERR(private->fb)) {
   378				DRM_ERROR("failed to initialize drm fb\n");
   379				private->fb = NULL;
   380			}
   381		}
   382		if (!private->fb)
   383			dev_info(&pdev->dev, "fbdev is not initialized\n");
   384	
   385		drm_kms_helper_poll_init(drm);
   386	
   387		drm_helper_disable_unused_functions(drm);
   388	
   389		platform_set_drvdata(pdev, private);
   390	
   391		if (match) {
   392			ret = component_master_add_with_match(drm->dev,
   393							      &xilinx_drm_ops, match);
   394			if (ret)
   395				goto err_fb;
   396		}
   397	
   398		ret = dma_set_coherent_mask(&pdev->dev,
   399					    DMA_BIT_MASK(sizeof(dma_addr_t) * 8));
   400		if (ret) {
 > 401			dev_info(&pdev->dev, "failed to set coherent mask (%lu)\n",
   402				 sizeof(dma_addr_t));
   403		}
   404	
   405		return 0;
   406	
   407	err_fb:
   408		drm_vblank_cleanup(drm);
   409	err_master:
   410		component_master_del(drm->dev, &xilinx_drm_ops);
   411	err_out:
   412		drm_mode_config_cleanup(drm);
   413		if (ret == -EPROBE_DEFER)
   414			DRM_INFO("load() is defered & will be called again\n");
   415		return ret;
   416	}
   417	

---
0-DAY kernel test infrastructure                Open Source Technology Center
https://lists.01.org/pipermail/kbuild-all                   Intel Corporation
-------------- next part --------------
A non-text attachment was scrubbed...
Name: .config.gz
Type: application/gzip
Size: 57103 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20171214/ee33c5e2/attachment-0001.gz>

^ permalink raw reply

* [PATCH 00/12] Marvell NAND controller rework with ->exec_op()
From: Boris Brezillon @ 2017-12-14  6:09 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20171207201814.30411-1-miquel.raynal@free-electrons.com>

Hi,

On Thu,  7 Dec 2017 21:18:02 +0100
Miquel Raynal <miquel.raynal@free-electrons.com> wrote:

> Hi,
> 
> After the addition of the NAND framework ->exec_op() interface (see [1]
> for the series preparing it and [2] for the last version of the
> core-side implementation of ->exec_op() itself), this series replaces
> the current Marvell NAND controller driver pxa3xx_nand.c with a rework
> called marvell_nand.c.
> 
> Aside the fact that it drops the big state machine, improves the overall
> speed and implements raw accesses, it is the first driver-side
> implementation of the ->exec_op() interface and may be used as reference
> for latter reworks of the same type.
> 
> One may find more detail about why a completely new driver is needed in
> the commit log of:
> 
>     "mtd: nand: add reworked Marvell NAND controller driver"
> 
> The series also changes the device tree NAND node definition for all
> platforms referring to the Marvell driver to use the new bindings. They
> are more hierarchical and fit the real organization of the hardware, by
> having NAND partitions that are part of NAND chip nodes, themselves part
> of the NAND controller node.
> 
> These changes have been tested on:
>    - PXA3xx platform with a CM-X300 board (2kiB page NAND, 1b/512B
>      strength, Hamming ECC engine) [32 bits]
>    - Armada 385 DB AP (4kiB page NAND, 4b/512B, BCH ECC engine) [32 bits]
>    - Armada 398 DB (4kiB page NAND, 8b/512B, BCH ECC engine using a layout
>      with a last chunk different than the others) [32 bits]
>    - Armada 7040 DB and Armada 8040 DB (4kiB page NAND, 4b/512B, BCH ECC
>      engine) [64 bits]
> 
> Robert, it would be great if you could also do more testing on PXA and
> validate this driver. If needed, a branch ready to be tested is
> available at [3]. It is based on nand/next and has all the changes
> brought by the previously mentionned series as well as this one.

Robert, do you think you'll have some time to test Miquel's branch on
your PXA boards? Miquel already tested on one of these boards (CM-X300),
but we'd like to have other testers. Also feel free to review the
driver if have the time.

Thanks,

Boris

> 
> Thank you,
> Miqu?l
> 
> 
> [1] https://www.spinics.net/lists/arm-kernel/msg619633.html
> [2] http://lists.infradead.org/pipermail/linux-mtd/2017-December/077965.html
> [3] https://github.com/miquelraynal/linux/tree/marvell/nand-next/nfc-rework
> 
> Miquel Raynal (12):
>   dt-bindings: mtd: add Marvell NAND controller documentation
>   mtd: nand: add reworked Marvell NAND controller driver
>   mtd: nand: replace pxa3xx_nand driver by its rework called
>     marvell_nand
>   dt-bindings: mtd: remove pxa3xx NAND controller documentation
>   mtd: nand: remove useless fields from pxa3xx NAND platform data
>   ARM: dts: armada-370-xp: use reworked NAND controller driver
>   ARM: dts: armada-375: use reworked NAND controller driver
>   ARM: dts: armada-38x: use reworked NAND controller driver
>   ARM: dts: armada-39x: use reworked NAND controller driver
>   ARM: dts: pxa: use reworked NAND controller driver
>   ARM64: dts: marvell: use reworked NAND controller driver on Armada 7K
>   ARM64: dts: marvell: use reworked NAND controller driver on Armada 8K
> 
>  .../devicetree/bindings/mtd/marvell-nand.txt       |   84 +
>  .../devicetree/bindings/mtd/pxa3xx-nand.txt        |   50 -
>  arch/arm/boot/dts/armada-370-db.dts                |   57 +-
>  arch/arm/boot/dts/armada-370-dlink-dns327l.dts     |  120 +-
>  arch/arm/boot/dts/armada-370-mirabox.dts           |   51 +-
>  arch/arm/boot/dts/armada-370-netgear-rn102.dts     |   90 +-
>  arch/arm/boot/dts/armada-370-netgear-rn104.dts     |   90 +-
>  arch/arm/boot/dts/armada-370-rd.dts                |   52 +-
>  arch/arm/boot/dts/armada-370-seagate-nas-xbay.dtsi |   64 +-
>  arch/arm/boot/dts/armada-370-xp.dtsi               |    6 +-
>  arch/arm/boot/dts/armada-375-db.dts                |   50 +-
>  arch/arm/boot/dts/armada-375.dtsi                  |    6 +-
>  arch/arm/boot/dts/armada-385-db-ap.dts             |   69 +-
>  arch/arm/boot/dts/armada-385-linksys-caiman.dts    |  129 +-
>  arch/arm/boot/dts/armada-385-linksys-cobra.dts     |  129 +-
>  arch/arm/boot/dts/armada-385-linksys-rango.dts     |  141 +-
>  arch/arm/boot/dts/armada-385-linksys-shelby.dts    |  129 +-
>  arch/arm/boot/dts/armada-385-linksys.dtsi          |   16 +-
>  arch/arm/boot/dts/armada-388-db.dts                |   55 +-
>  arch/arm/boot/dts/armada-38x.dtsi                  |    6 +-
>  arch/arm/boot/dts/armada-390-db.dts                |   66 +-
>  arch/arm/boot/dts/armada-395-gp.dts                |   74 +-
>  arch/arm/boot/dts/armada-398-db.dts                |   60 +-
>  arch/arm/boot/dts/armada-39x.dtsi                  |    6 +-
>  arch/arm/boot/dts/armada-xp-db-dxbc2.dts           |    2 +-
>  arch/arm/boot/dts/armada-xp-db-xc3-24g4xg.dts      |    2 +-
>  arch/arm/boot/dts/armada-xp-db.dts                 |    2 +-
>  arch/arm/boot/dts/armada-xp-gp.dts                 |    2 +-
>  arch/arm/boot/dts/armada-xp-lenovo-ix4-300d.dts    |    2 +-
>  arch/arm/boot/dts/armada-xp-linksys-mamba.dts      |  156 +-
>  arch/arm/boot/dts/armada-xp-netgear-rn2120.dts     |   90 +-
>  arch/arm/boot/dts/pxa3xx.dtsi                      |    6 +-
>  arch/arm/configs/cm_x300_defconfig                 |    2 +-
>  arch/arm/configs/mvebu_v7_defconfig                |    2 +-
>  arch/arm/configs/pxa3xx_defconfig                  |    3 +-
>  arch/arm/configs/pxa_defconfig                     |    2 +-
>  arch/arm/configs/raumfeld_defconfig                |    2 +-
>  arch/arm/mach-mmp/ttc_dkb.c                        |    4 +-
>  arch/arm/mach-pxa/cm-x300.c                        |    8 +-
>  arch/arm/mach-pxa/colibri-pxa3xx.c                 |    8 +-
>  arch/arm/mach-pxa/colibri.h                        |    2 +-
>  arch/arm/mach-pxa/littleton.c                      |   10 +-
>  arch/arm/mach-pxa/mxm8x10.c                        |   10 +-
>  arch/arm/mach-pxa/raumfeld.c                       |    6 +-
>  arch/arm/mach-pxa/zylonite.c                       |   10 +-
>  arch/arm64/boot/dts/marvell/armada-7040-db.dts     |   52 +-
>  arch/arm64/boot/dts/marvell/armada-8040-db.dts     |   46 +-
>  .../boot/dts/marvell/armada-cp110-master.dtsi      |    8 +-
>  .../arm64/boot/dts/marvell/armada-cp110-slave.dtsi |   10 +-
>  drivers/mtd/nand/Kconfig                           |   12 +
>  drivers/mtd/nand/Makefile                          |    2 +-
>  drivers/mtd/nand/marvell_nand.c                    | 2950 ++++++++++++++++++++
>  drivers/mtd/nand/pxa3xx_nand.c                     | 2104 --------------
>  include/linux/platform_data/mtd-nand-pxa3xx.h      |   43 +-
>  54 files changed, 4093 insertions(+), 3065 deletions(-)
>  create mode 100644 Documentation/devicetree/bindings/mtd/marvell-nand.txt
>  delete mode 100644 Documentation/devicetree/bindings/mtd/pxa3xx-nand.txt
>  create mode 100644 drivers/mtd/nand/marvell_nand.c
>  delete mode 100644 drivers/mtd/nand/pxa3xx_nand.c
> 

^ permalink raw reply

* [PATCH 1/1] arm: sunxi: Add alternative pins for spi0
From: Stefan Mavrodiev @ 2017-12-14  6:24 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20171213154035.qc655iahjoeflftq@flea.lan>

On 12/13/2017 05:40 PM, Maxime Ripard wrote:
> Hi,
>
> On Wed, Dec 13, 2017 at 09:44:34AM +0200, Stefan Mavrodiev wrote:
>> Allwinner A10/A13/A20 SoCs have pinmux for spi0
>> on port C. The patch adds these pins in the respective
>> dts includes.
>>
>> Signed-off-by: Stefan Mavrodiev <stefan@olimex.com>
> Do you have any boards that are using these?
>
> We won't merge that patch if there's no users for it.
>
> Maxime
>
A20-OLinuXino-Lime/Lime2 and A10-OLinuXino-Lime with spi flash.
For A13 we still doesn't have that option.

^ permalink raw reply

* [PATCH v4 00/15] drm/sun4i: Add A83t LVDS support
From: Priit Laes @ 2017-12-14  7:01 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <cover.e46a07c0e181d735c807dc94fe0ce0ea013788be.1512662253.git-series.maxime.ripard@free-electrons.com>

On Thu, Dec 07, 2017 at 04:58:45PM +0100, Maxime Ripard wrote:
> Hi,
> 
> Here is an attempt at supporting the LVDS output in our DRM driver. This
> has been tested on the A83T (with DE2), but since everything is basically
> in the TCON, it should also be usable on the older SoCs with minor
> modifications.

I managed to get the single-channel LVDS working on an A10 tablet after
doing those minor modifications (although, the colours are off a bit).
So in general this series looks good :)

> 
> This was the occasion to refactor a bunch of things. The most notable ones
> would be the documentation, and split of the UI layers in the mixer code,
> and the switch to kfifo for our endpoint parsing code in the driver that
> fixes an issue introduced by the switch to BFS.
> 
> Let me know what you think,
> Maxime
> 
> Changes from v3:
>   - Collect the tags
>   - Use SPDX headers when possible
>   - Added the new mixer configuration options
>   - Changed the LVDS clock for lvds-alt instead of lvds-pll
>   - Removed the MIPI PLL from the A31s
>   - Changed the LVDS_ANA0 macros name to reflect the generation they were
>     introduced in, and added a comment to mention the changes needed to
>     support the older SoCs
> 
> Changes from v2:
>   - Move the module clock rate to the mixer structure
>   - Adjusted the simple-panel documentation for power-supply
>   - Changed the compatible for the first A83t mixer to mixer 0
>   - Rebased on top of current drm-misc
>   - Split out the A83t bindings in its separate patch
> 
> Changes from v1:
>   - Added a fix for the error path handling in the TCON
>   - Enable the TCON by default
>   - Removed the patch that changes the channels offset but kept most of the
>     modifications as a cleanup
>   - Deal with the LVDS clock being able to have another PLL parent on some
>     SoCs
>   - Renamed the TCON compatible to TCON-TV, following the convention used
>     on newer SoCs
>   - Removed the hardcoded timings
>   - Moved LVDS enable quirks to a separate function
>   - Used clock indices define in the DT
>   - Removed the hardcoded clock rate in the DT and moved it to the driver
>   - Changed sun8i_mixer_planes to sun8i_mixer_ui_planes to be consistent
>   - Added the various tags collected
>   - Rebased on top of 4.15
> 
> Maxime Ripard (15):
>   dt-bindings: panel: lvds: Document power-supply property
>   drm/panel: lvds: Add support for the power-supply property
>   dt-bindings: display: sun4i-drm: Add LVDS properties
>   dt-bindings: display: sun4i-drm: Add A83T pipeline
>   drm/sun4i: Fix error path handling
>   drm/sun4i: Force the mixer rate at 150MHz
>   drm/sun4i: Create minimal multipliers and dividers
>   drm/sun4i: Add LVDS support
>   drm/sun4i: Add A83T support
>   ARM: dts: sun8i: a83t: Add display pipeline
>   ARM: dts: sun8i: a83t: Enable the PWM
>   ARM: dts: sun8i: a83t: Add LVDS pins group
>   ARM: dts: sun8i: a83t: Add the PWM pin group
>   ARM: dts: sun8i: a711: Reinstate the PMIC compatible
>   ARM: dts: sun8i: a711: Enable the LCD
> 
>  Documentation/devicetree/bindings/display/panel/panel-common.txt |   6 ++-
>  Documentation/devicetree/bindings/display/panel/panel-lvds.txt   |   1 +-
>  Documentation/devicetree/bindings/display/panel/simple-panel.txt |   2 +-
>  Documentation/devicetree/bindings/display/sunxi/sun4i-drm.txt    |  12 +++-
>  arch/arm/boot/dts/sun8i-a83t-tbs-a711.dts                        |  62 ++++++++++++++++++-
>  arch/arm/boot/dts/sun8i-a83t.dtsi                                |  99 ++++++++++++++++++++++++++++-
>  drivers/gpu/drm/panel/panel-lvds.c                               |  23 +++++++-
>  drivers/gpu/drm/sun4i/Makefile                                   |   1 +-
>  drivers/gpu/drm/sun4i/sun4i_dotclock.c                           |  10 ++-
>  drivers/gpu/drm/sun4i/sun4i_drv.c                                |   1 +-
>  drivers/gpu/drm/sun4i/sun4i_lvds.c                               | 177 +++++++++++++++++++++++++++++++++++++++++++++++++++-
>  drivers/gpu/drm/sun4i/sun4i_lvds.h                               |  18 +++++-
>  drivers/gpu/drm/sun4i/sun4i_tcon.c                               | 251 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
>  drivers/gpu/drm/sun4i/sun4i_tcon.h                               |  31 +++++++++-
>  drivers/gpu/drm/sun4i/sun8i_mixer.c                              |  20 ++++++-
>  drivers/gpu/drm/sun4i/sun8i_mixer.h                              |   3 +-
>  16 files changed, 710 insertions(+), 7 deletions(-)
>  create mode 100644 drivers/gpu/drm/sun4i/sun4i_lvds.c
>  create mode 100644 drivers/gpu/drm/sun4i/sun4i_lvds.h
> 
> base-commit: 3b71239181e5429702387666f1ac70a9e6856cce
> -- 
> git-series 0.9.1

^ permalink raw reply

* [PATCH] Staging: vc04_services: fix brace coding style issues in vchiq_shim.c
From: Stefan Wahren @ 2017-12-14  7:33 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1513198282-62964-1-git-send-email-marek_tomas@centrum.cz>

Am 13.12.2017 um 21:51 schrieb Tomas Marek:
> This patch fix brace on next line coding style errors reported by
> checkpatch.
>
> Signed-off-by: Tomas Marek <marek_tomas@centrum.cz>

Acked-by: Stefan Wahren <stefan.wahren@i2se.com>

Thanks

^ permalink raw reply

* [PATCH 0/8] drm/sun4i: Support the Display Engine frontend
From: Maxime Ripard @ 2017-12-14  8:35 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <407ed605-6c02-fae5-7cc8-e6119b26d49f@vitsch.nl>

Hi Thomas,

On Wed, Dec 13, 2017 at 05:16:22PM +0100, Thomas van Kleef wrote:
> Hi,
> 
> On 13-12-17 16:33, Maxime Ripard wrote:
> > Hi,
> > 
> > This is a first serie to enable the display engine frontend.
> > 
> > This hardware block is found in the first generation Display Engine from
> > Allwinner. Its role is to implement more advanced features that the
> > associated backend, even though the backend alone can be used (and was used
> > so far) for basic composition.
> > 
> > Among those features, we will find hardware scaling, that is supported in
> > this serie, colorspace conversions, or more exotic formats support such as
> > the one output by the VPU.
>
> So, if I have read the code correctly. The frontend will be used whenever the
> input size differs from the output size.

Yes :)

My current plan is to extend it as needed when we'll need to deal with
a format not supported by the backend (for the VPU), or anything the
backend cannot support.

Maxime

-- 
Maxime Ripard, Free Electrons
Embedded Linux and Kernel engineering
http://free-electrons.com
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 833 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20171214/795427a7/attachment-0001.sig>

^ permalink raw reply

* [PATCH v4 00/15] drm/sun4i: Add A83t LVDS support
From: Maxime Ripard @ 2017-12-14  8:37 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20171214070157.rqx4tfpluzaqmtxu@plaes.org>

On Thu, Dec 14, 2017 at 07:01:57AM +0000, Priit Laes wrote:
> On Thu, Dec 07, 2017 at 04:58:45PM +0100, Maxime Ripard wrote:
> > Hi,
> > 
> > Here is an attempt at supporting the LVDS output in our DRM driver. This
> > has been tested on the A83T (with DE2), but since everything is basically
> > in the TCON, it should also be usable on the older SoCs with minor
> > modifications.
> 
> I managed to get the single-channel LVDS working on an A10 tablet after
> doing those minor modifications (although, the colours are off a bit).
> So in general this series looks good :)

Is that a Tested-by? :)

Maxime

-- 
Maxime Ripard, Free Electrons
Embedded Linux and Kernel engineering
http://free-electrons.com
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 833 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20171214/8299378d/attachment.sig>

^ permalink raw reply

* [PATCH v2 07/19] arm64: insn: Add encoder for bitwise operations using litterals
From: Marc Zyngier @ 2017-12-14  8:40 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <5A314AFF.60300@arm.com>

On 13/12/17 15:45, James Morse wrote:
> Hi Marc,
> 
> On 13/12/17 14:32, Marc Zyngier wrote:
>> On 12/12/17 18:32, James Morse wrote:
>>> On 11/12/17 14:49, Marc Zyngier wrote:
>>>> We lack a way to encode operations such as AND, ORR, EOR that take
>>>> an immediate value. Doing so is quite involved, and is all about
>>>> reverse engineering the decoding algorithm described in the
>>>> pseudocode function DecodeBitMasks().
> 
>>>> diff --git a/arch/arm64/kernel/insn.c b/arch/arm64/kernel/insn.c
>>>> index 7e432662d454..326b17016485 100644
>>>> --- a/arch/arm64/kernel/insn.c
>>>> +++ b/arch/arm64/kernel/insn.c
>>>
>>>> +static u32 aarch64_encode_immediate(u64 imm,
>>>> +				    enum aarch64_insn_variant variant,
>>>> +				    u32 insn)
>>>> +{
>>>> +	unsigned int immr, imms, n, ones, ror, esz, tmp;
>>>> +	u64 mask;
>>>
>>> [...]
>>>
>>>> +	/* Compute the rotation */
>>>> +	if (range_of_ones(imm)) {
>>>> +		/*
>>>> +		 * Pattern: 0..01..10..0
>>>> +		 *
>>>> +		 * Compute how many rotate we need to align it right
>>>> +		 */
>>>> +		ror = ffs(imm) - 1;
>>>
>>> (how come range_of_ones() uses __ffs64() on the same value?)
>>
>> News flash: range_of_ones is completely buggy. It will fail on the 
>> trivial value 1 (__ffs64(1) = 0; 0 - 1 = -1; val >> -1 is... ermmmm).
>> I definitely got mixed up between the two.
> 
> They do different things!? Aaaaaahhhh....
> 
> [ ...]
> 
>>> Unless I've gone wrong, I think the 'Trim imm to the element size' code needs to
>>> move up into the esz-reducing loop so it doesn't happen for a 64bit immediate.
> 
> 
>> Yup. I've stashed the following patch:
>>
>> diff --git a/arch/arm64/kernel/insn.c b/arch/arm64/kernel/insn.c
>> index b8fb2d89b3a6..e58be1c57f18 100644
>> --- a/arch/arm64/kernel/insn.c
>> +++ b/arch/arm64/kernel/insn.c
>> @@ -1503,8 +1503,7 @@ pstate_check_t * const aarch32_opcode_cond_checks[16] = {
>>  static bool range_of_ones(u64 val)
>>  {
>>  	/* Doesn't handle full ones or full zeroes */
>> -	int x = __ffs64(val) - 1;
>> -	u64 sval = val >> x;
>> +	u64 sval = val >> __ffs64(val);
>>  
>>  	/* One of Sean Eron Anderson's bithack tricks */
>>  	return ((sval + 1) & (sval)) == 0;
>> @@ -1515,7 +1514,7 @@ static u32 aarch64_encode_immediate(u64 imm,
>>  				    u32 insn)
>>  {
>>  	unsigned int immr, imms, n, ones, ror, esz, tmp;
>> -	u64 mask;
>> +	u64 mask = ~0UL;
>>  
>>  	/* Can't encode full zeroes or full ones */
>>  	if (!imm || !~imm)
>> @@ -1543,8 +1542,12 @@ static u32 aarch64_encode_immediate(u64 imm,
>>  	for (tmp = esz; tmp > 2; tmp /= 2) {
>>  		u64 emask = BIT(tmp / 2) - 1;
>>  
>> -		if ((imm & emask) != ((imm >> (tmp / 2)) & emask))
>> +		if ((imm & emask) != ((imm >> (tmp / 2)) & emask)) {
>> +			/* Trim imm to the element size */
>> +			mask = BIT(esz - 1) - 1;
>> +			imm &= mask;
> 
> Won't this still lose the top bit? It generates 0x7fffffff for esz=32, and for
> esz=32 we run through here when the two 16bit values are different.
> 
> This still runs for a 64bit immediate. The 0xf80000000fffffff example compares
> 0xf8000000 with 0fffffff then breaks here on the first iteration of this loop.
> With this change it still attempts to generate a 64bit mask.
> 
> I was thinking of something like [0]. That only runs when we know the two
> tmp:halves match, it just keeps the bottom tmp:half for the next run and never
> runs for a 64bit immediate.
> 
> 
>>  			break;
>> +		}
>>  
>>  		esz = tmp;
>>  	}
>> @@ -1552,10 +1555,6 @@ static u32 aarch64_encode_immediate(u64 imm,
>>  	/* N is only set if we're encoding a 64bit value */
>>  	n = esz == 64;
>>  
>> -	/* Trim imm to the element size */
>> -	mask = BIT(esz - 1) - 1;
>> -	imm &= mask;
>> -
>>  	/* That's how many ones we need to encode */
>>  	ones = hweight64(imm);
>>  
>> I really need to run this against gas in order to make sure
>> I get the same parameters for all the possible values.
> 
> Sounds good,
> 
> 
> Thanks,
> 
> James
> 
> 
> [0] Not even built:
> diff --git a/arch/arm64/kernel/insn.c b/arch/arm64/kernel/insn.c
> index 12d3ec2154c2..d9fbdea7b18d 100644
> --- a/arch/arm64/kernel/insn.c
> +++ b/arch/arm64/kernel/insn.c
> @@ -1529,15 +1529,15 @@ static u32 aarch64_encode_immediate(u64 imm,
>                         break;
> 
>                 esz = tmp;
> +
> +               /* Trim imm to the element size */
> +               mask = BIT(esz) - 1;
> +               imm &= mask;

This should go together with a small adjustment of the narrowing loop,
as we never hit esz==2, which is a bit of a problem.

I now have a small test rig generating all the valid immediates and
comparing the encodings with GAS, which helped figuring out the bugs.

Thanks,

	M.
-- 
Jazz is not dead. It just smells funny...

^ permalink raw reply

* [PATCH v9 00/13] Add STM32 DFSDM support
From: Arnaud Pouliquen @ 2017-12-14  8:57 UTC (permalink / raw)
  To: linux-arm-kernel

Hello

New version to fix patch 10/13: IIO: ADC: add stm32 DFSDM support for PDM microphone

Main deltas V9 vs V8:
- Rework probe and remove order for audio configuration in stm32-dfsdm-adc.c.
- Optimization of the filling of the dma_slave_config struct.

Main deltas V8 vs V7:
- Few typos fixes.
- Function return optimizations in sound/soc/stm/stm32_adfsdm.c.

Main deltas V7 vs V6:
- Replaces the custom license information text with the appropriate 
  SPDX identifier.
- Few fixes in sound/soc/stm/stm32_adfsdm.c and stm32-dfsdm-core.c.
- Add missing #interrupt-cells in binding examples.
- Integrate last Jonathan's comments.

Main deltas V6 vs V5:
- Fix warning reported by kbuild test in :
   include/linux/iio/consumer.h
   sound/soc/stm/stm32_adfsdm.c

Main deltas V5 vs V4:
- Integrate ASOC DAI as a subnode of the DFSDM.
- Add in kernel consumer interface to allow to manipulate attribute.

Thanks,
Arnaud

Arnaud Pouliquen (12):
  docs: driver-api: add iio hw consumer section
  IIO: hw_consumer: add devm_iio_hw_consumer_alloc
  IIO: inkern: API for manipulating channel attributes
  IIO: Add DT bindings for sigma delta adc modulator
  IIO: ADC: add sigma delta modulator support
  IIO: add DT bindings for stm32 DFSDM filter
  IIO: ADC: add stm32 DFSDM core support
  IIO: ADC: add STM32 DFSDM sigma delta ADC support
  IIO: ADC: add stm32 DFSDM support for PDM microphone
  IIO: consumer: allow to set buffer sizes
  ASoC: add bindings for stm32 DFSDM filter
  ASoC: stm32: add DFSDM DAI support

Lars-Peter Clausen (1):
  iio: Add hardware consumer buffer support

 .../ABI/testing/sysfs-bus-iio-dfsdm-adc-stm32      |   16 +
 .../bindings/iio/adc/sigma-delta-modulator.txt     |   13 +
 .../bindings/iio/adc/st,stm32-dfsdm-adc.txt        |  128 +++
 .../devicetree/bindings/sound/st,stm32-adfsdm.txt  |   63 +
 Documentation/driver-api/iio/hw-consumer.rst       |   51 +
 Documentation/driver-api/iio/index.rst             |    1 +
 drivers/iio/adc/Kconfig                            |   37 +
 drivers/iio/adc/Makefile                           |    3 +
 drivers/iio/adc/sd_adc_modulator.c                 |   68 ++
 drivers/iio/adc/stm32-dfsdm-adc.c                  | 1216 ++++++++++++++++++++
 drivers/iio/adc/stm32-dfsdm-core.c                 |  309 +++++
 drivers/iio/adc/stm32-dfsdm.h                      |  310 +++++
 drivers/iio/buffer/Kconfig                         |   10 +
 drivers/iio/buffer/Makefile                        |    1 +
 drivers/iio/buffer/industrialio-buffer-cb.c        |   11 +
 drivers/iio/buffer/industrialio-hw-consumer.c      |  247 ++++
 drivers/iio/inkern.c                               |   17 +-
 include/linux/iio/adc/stm32-dfsdm-adc.h            |   18 +
 include/linux/iio/consumer.h                       |   37 +
 include/linux/iio/hw-consumer.h                    |   21 +
 include/linux/iio/iio.h                            |   28 -
 include/linux/iio/types.h                          |   28 +
 sound/soc/stm/Kconfig                              |   11 +
 sound/soc/stm/Makefile                             |    3 +
 sound/soc/stm/stm32_adfsdm.c                       |  347 ++++++
 25 files changed, 2961 insertions(+), 33 deletions(-)
 create mode 100644 Documentation/ABI/testing/sysfs-bus-iio-dfsdm-adc-stm32
 create mode 100644 Documentation/devicetree/bindings/iio/adc/sigma-delta-modulator.txt
 create mode 100644 Documentation/devicetree/bindings/iio/adc/st,stm32-dfsdm-adc.txt
 create mode 100644 Documentation/devicetree/bindings/sound/st,stm32-adfsdm.txt
 create mode 100644 Documentation/driver-api/iio/hw-consumer.rst
 create mode 100644 drivers/iio/adc/sd_adc_modulator.c
 create mode 100644 drivers/iio/adc/stm32-dfsdm-adc.c
 create mode 100644 drivers/iio/adc/stm32-dfsdm-core.c
 create mode 100644 drivers/iio/adc/stm32-dfsdm.h
 create mode 100644 drivers/iio/buffer/industrialio-hw-consumer.c
 create mode 100644 include/linux/iio/adc/stm32-dfsdm-adc.h
 create mode 100644 include/linux/iio/hw-consumer.h
 create mode 100644 sound/soc/stm/stm32_adfsdm.c

-- 
2.7.4

^ permalink raw reply

* [PATCH v9 01/13] iio: Add hardware consumer buffer support
From: Arnaud Pouliquen @ 2017-12-14  8:57 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1513241885-32079-1-git-send-email-arnaud.pouliquen@st.com>

From: Lars-Peter Clausen <lars@metafoo.de>

Hardware consumer interface can be used when one IIO device has
a direct connection to another device in hardware.

Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Signed-off-by: Arnaud Pouliquen <arnaud.pouliquen@st.com>
Reviewed-by: Jonathan Cameron <Jonathan.Cameron@huawei.com>
---
 drivers/iio/buffer/Kconfig                    |  10 ++
 drivers/iio/buffer/Makefile                   |   1 +
 drivers/iio/buffer/industrialio-hw-consumer.c | 181 ++++++++++++++++++++++++++
 include/linux/iio/hw-consumer.h               |  19 +++
 4 files changed, 211 insertions(+)
 create mode 100644 drivers/iio/buffer/industrialio-hw-consumer.c
 create mode 100644 include/linux/iio/hw-consumer.h

diff --git a/drivers/iio/buffer/Kconfig b/drivers/iio/buffer/Kconfig
index 4ffd3db..338774c 100644
--- a/drivers/iio/buffer/Kconfig
+++ b/drivers/iio/buffer/Kconfig
@@ -29,6 +29,16 @@ config IIO_BUFFER_DMAENGINE
 
 	  Should be selected by drivers that want to use this functionality.
 
+config IIO_BUFFER_HW_CONSUMER
+	tristate "Industrial I/O HW buffering"
+	help
+	  Provides a way to bonding when an IIO device has a direct connection
+	  to another device in hardware. In this case buffers for data transfers
+	  are handled by hardware.
+
+	  Should be selected by drivers that want to use the generic Hw consumer
+	  interface.
+
 config IIO_KFIFO_BUF
 	tristate "Industrial I/O buffering based on kfifo"
 	help
diff --git a/drivers/iio/buffer/Makefile b/drivers/iio/buffer/Makefile
index 85beaae..324a36b 100644
--- a/drivers/iio/buffer/Makefile
+++ b/drivers/iio/buffer/Makefile
@@ -6,5 +6,6 @@
 obj-$(CONFIG_IIO_BUFFER_CB) += industrialio-buffer-cb.o
 obj-$(CONFIG_IIO_BUFFER_DMA) += industrialio-buffer-dma.o
 obj-$(CONFIG_IIO_BUFFER_DMAENGINE) += industrialio-buffer-dmaengine.o
+obj-$(CONFIG_IIO_BUFFER_HW_CONSUMER) += industrialio-hw-consumer.o
 obj-$(CONFIG_IIO_TRIGGERED_BUFFER) += industrialio-triggered-buffer.o
 obj-$(CONFIG_IIO_KFIFO_BUF) += kfifo_buf.o
diff --git a/drivers/iio/buffer/industrialio-hw-consumer.c b/drivers/iio/buffer/industrialio-hw-consumer.c
new file mode 100644
index 0000000..993ecdc
--- /dev/null
+++ b/drivers/iio/buffer/industrialio-hw-consumer.c
@@ -0,0 +1,181 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright 2017 Analog Devices Inc.
+ *  Author: Lars-Peter Clausen <lars@metafoo.de>
+ */
+
+#include <linux/err.h>
+#include <linux/export.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+
+#include <linux/iio/iio.h>
+#include <linux/iio/consumer.h>
+#include <linux/iio/hw-consumer.h>
+#include <linux/iio/buffer_impl.h>
+
+/**
+ * struct iio_hw_consumer - IIO hw consumer block
+ * @buffers: hardware buffers list head.
+ * @channels: IIO provider channels.
+ */
+struct iio_hw_consumer {
+	struct list_head buffers;
+	struct iio_channel *channels;
+};
+
+struct hw_consumer_buffer {
+	struct list_head head;
+	struct iio_dev *indio_dev;
+	struct iio_buffer buffer;
+	long scan_mask[];
+};
+
+static struct hw_consumer_buffer *iio_buffer_to_hw_consumer_buffer(
+	struct iio_buffer *buffer)
+{
+	return container_of(buffer, struct hw_consumer_buffer, buffer);
+}
+
+static void iio_hw_buf_release(struct iio_buffer *buffer)
+{
+	struct hw_consumer_buffer *hw_buf =
+		iio_buffer_to_hw_consumer_buffer(buffer);
+	kfree(hw_buf);
+}
+
+static const struct iio_buffer_access_funcs iio_hw_buf_access = {
+	.release = &iio_hw_buf_release,
+	.modes = INDIO_BUFFER_HARDWARE,
+};
+
+static struct hw_consumer_buffer *iio_hw_consumer_get_buffer(
+	struct iio_hw_consumer *hwc, struct iio_dev *indio_dev)
+{
+	size_t mask_size = BITS_TO_LONGS(indio_dev->masklength) * sizeof(long);
+	struct hw_consumer_buffer *buf;
+
+	list_for_each_entry(buf, &hwc->buffers, head) {
+		if (buf->indio_dev == indio_dev)
+			return buf;
+	}
+
+	buf = kzalloc(sizeof(*buf) + mask_size, GFP_KERNEL);
+	if (!buf)
+		return NULL;
+
+	buf->buffer.access = &iio_hw_buf_access;
+	buf->indio_dev = indio_dev;
+	buf->buffer.scan_mask = buf->scan_mask;
+
+	iio_buffer_init(&buf->buffer);
+	list_add_tail(&buf->head, &hwc->buffers);
+
+	return buf;
+}
+
+/**
+ * iio_hw_consumer_alloc() - Allocate IIO hardware consumer
+ * @dev: Pointer to consumer device.
+ *
+ * Returns a valid iio_hw_consumer on success or a ERR_PTR() on failure.
+ */
+struct iio_hw_consumer *iio_hw_consumer_alloc(struct device *dev)
+{
+	struct hw_consumer_buffer *buf;
+	struct iio_hw_consumer *hwc;
+	struct iio_channel *chan;
+	int ret;
+
+	hwc = kzalloc(sizeof(*hwc), GFP_KERNEL);
+	if (!hwc)
+		return ERR_PTR(-ENOMEM);
+
+	INIT_LIST_HEAD(&hwc->buffers);
+
+	hwc->channels = iio_channel_get_all(dev);
+	if (IS_ERR(hwc->channels)) {
+		ret = PTR_ERR(hwc->channels);
+		goto err_free_hwc;
+	}
+
+	chan = &hwc->channels[0];
+	while (chan->indio_dev) {
+		buf = iio_hw_consumer_get_buffer(hwc, chan->indio_dev);
+		if (!buf) {
+			ret = -ENOMEM;
+			goto err_put_buffers;
+		}
+		set_bit(chan->channel->scan_index, buf->buffer.scan_mask);
+		chan++;
+	}
+
+	return hwc;
+
+err_put_buffers:
+	list_for_each_entry(buf, &hwc->buffers, head)
+		iio_buffer_put(&buf->buffer);
+	iio_channel_release_all(hwc->channels);
+err_free_hwc:
+	kfree(hwc);
+	return ERR_PTR(ret);
+}
+EXPORT_SYMBOL_GPL(iio_hw_consumer_alloc);
+
+/**
+ * iio_hw_consumer_free() - Free IIO hardware consumer
+ * @hwc: hw consumer to free.
+ */
+void iio_hw_consumer_free(struct iio_hw_consumer *hwc)
+{
+	struct hw_consumer_buffer *buf, *n;
+
+	iio_channel_release_all(hwc->channels);
+	list_for_each_entry_safe(buf, n, &hwc->buffers, head)
+		iio_buffer_put(&buf->buffer);
+	kfree(hwc);
+}
+EXPORT_SYMBOL_GPL(iio_hw_consumer_free);
+
+/**
+ * iio_hw_consumer_enable() - Enable IIO hardware consumer
+ * @hwc: iio_hw_consumer to enable.
+ *
+ * Returns 0 on success.
+ */
+int iio_hw_consumer_enable(struct iio_hw_consumer *hwc)
+{
+	struct hw_consumer_buffer *buf;
+	int ret;
+
+	list_for_each_entry(buf, &hwc->buffers, head) {
+		ret = iio_update_buffers(buf->indio_dev, &buf->buffer, NULL);
+		if (ret)
+			goto err_disable_buffers;
+	}
+
+	return 0;
+
+err_disable_buffers:
+	list_for_each_entry_continue_reverse(buf, &hwc->buffers, head)
+		iio_update_buffers(buf->indio_dev, NULL, &buf->buffer);
+	return ret;
+}
+EXPORT_SYMBOL_GPL(iio_hw_consumer_enable);
+
+/**
+ * iio_hw_consumer_disable() - Disable IIO hardware consumer
+ * @hwc: iio_hw_consumer to disable.
+ */
+void iio_hw_consumer_disable(struct iio_hw_consumer *hwc)
+{
+	struct hw_consumer_buffer *buf;
+
+	list_for_each_entry(buf, &hwc->buffers, head)
+		iio_update_buffers(buf->indio_dev, NULL, &buf->buffer);
+}
+EXPORT_SYMBOL_GPL(iio_hw_consumer_disable);
+
+MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>");
+MODULE_DESCRIPTION("Hardware consumer buffer the IIO framework");
+MODULE_LICENSE("GPL v2");
diff --git a/include/linux/iio/hw-consumer.h b/include/linux/iio/hw-consumer.h
new file mode 100644
index 0000000..db8c00b
--- /dev/null
+++ b/include/linux/iio/hw-consumer.h
@@ -0,0 +1,19 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Industrial I/O in kernel hardware consumer interface
+ *
+ * Copyright 2017 Analog Devices Inc.
+ *  Author: Lars-Peter Clausen <lars@metafoo.de>
+ */
+
+#ifndef LINUX_IIO_HW_CONSUMER_H
+#define LINUX_IIO_HW_CONSUMER_H
+
+struct iio_hw_consumer;
+
+struct iio_hw_consumer *iio_hw_consumer_alloc(struct device *dev);
+void iio_hw_consumer_free(struct iio_hw_consumer *hwc);
+int iio_hw_consumer_enable(struct iio_hw_consumer *hwc);
+void iio_hw_consumer_disable(struct iio_hw_consumer *hwc);
+
+#endif
-- 
2.7.4

^ permalink raw reply related

* [PATCH v9 02/13] docs: driver-api: add iio hw consumer section
From: Arnaud Pouliquen @ 2017-12-14  8:57 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1513241885-32079-1-git-send-email-arnaud.pouliquen@st.com>

This adds a section about the Hardware consumer
API of the IIO subsystem to the driver API
documentation.

Signed-off-by: Arnaud Pouliquen <arnaud.pouliquen@st.com>
Reviewed-by: Jonathan Cameron <Jonathan.Cameron@huawei.com>
---
 Documentation/driver-api/iio/hw-consumer.rst | 51 ++++++++++++++++++++++++++++
 Documentation/driver-api/iio/index.rst       |  1 +
 2 files changed, 52 insertions(+)
 create mode 100644 Documentation/driver-api/iio/hw-consumer.rst

diff --git a/Documentation/driver-api/iio/hw-consumer.rst b/Documentation/driver-api/iio/hw-consumer.rst
new file mode 100644
index 0000000..8facce6
--- /dev/null
+++ b/Documentation/driver-api/iio/hw-consumer.rst
@@ -0,0 +1,51 @@
+===========
+HW consumer
+===========
+An IIO device can be directly connected to another device in hardware. in this
+case the buffers between IIO provider and IIO consumer are handled by hardware.
+The Industrial I/O HW consumer offers a way to bond these IIO devices without
+software buffer for data. The implementation can be found under
+:file:`drivers/iio/buffer/hw-consumer.c`
+
+
+* struct :c:type:`iio_hw_consumer` ? Hardware consumer structure
+* :c:func:`iio_hw_consumer_alloc` ? Allocate IIO hardware consumer
+* :c:func:`iio_hw_consumer_free` ? Free IIO hardware consumer
+* :c:func:`iio_hw_consumer_enable` ? Enable IIO hardware consumer
+* :c:func:`iio_hw_consumer_disable` ? Disable IIO hardware consumer
+
+
+HW consumer setup
+=================
+
+As standard IIO device the implementation is based on IIO provider/consumer.
+A typical IIO HW consumer setup looks like this::
+
+	static struct iio_hw_consumer *hwc;
+
+	static const struct iio_info adc_info = {
+		.read_raw = adc_read_raw,
+	};
+
+	static int adc_read_raw(struct iio_dev *indio_dev,
+				struct iio_chan_spec const *chan, int *val,
+				int *val2, long mask)
+	{
+		ret = iio_hw_consumer_enable(hwc);
+
+		/* Acquire data */
+
+		ret = iio_hw_consumer_disable(hwc);
+	}
+
+	static int adc_probe(struct platform_device *pdev)
+	{
+		hwc = devm_iio_hw_consumer_alloc(&iio->dev);
+	}
+
+More details
+============
+.. kernel-doc:: include/linux/iio/hw-consumer.h
+.. kernel-doc:: drivers/iio/buffer/industrialio-hw-consumer.c
+   :export:
+
diff --git a/Documentation/driver-api/iio/index.rst b/Documentation/driver-api/iio/index.rst
index e5c3922..7fba341 100644
--- a/Documentation/driver-api/iio/index.rst
+++ b/Documentation/driver-api/iio/index.rst
@@ -15,3 +15,4 @@ Contents:
    buffers
    triggers
    triggered-buffers
+   hw-consumer
-- 
2.7.4

^ permalink raw reply related

* [PATCH v9 03/13] IIO: hw_consumer: add devm_iio_hw_consumer_alloc
From: Arnaud Pouliquen @ 2017-12-14  8:57 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1513241885-32079-1-git-send-email-arnaud.pouliquen@st.com>

Add devm_iio_hw_consumer_alloc function that calls iio_hw_consumer_free
when the device is unbound from the bus.

Signed-off-by: Arnaud Pouliquen <arnaud.pouliquen@st.com>
Reviewed-by: Jonathan Cameron <Jonathan.Cameron@huawei.com>
---
 drivers/iio/buffer/industrialio-hw-consumer.c | 66 +++++++++++++++++++++++++++
 include/linux/iio/hw-consumer.h               |  2 +
 2 files changed, 68 insertions(+)

diff --git a/drivers/iio/buffer/industrialio-hw-consumer.c b/drivers/iio/buffer/industrialio-hw-consumer.c
index 993ecdc..9516569 100644
--- a/drivers/iio/buffer/industrialio-hw-consumer.c
+++ b/drivers/iio/buffer/industrialio-hw-consumer.c
@@ -137,6 +137,72 @@ void iio_hw_consumer_free(struct iio_hw_consumer *hwc)
 }
 EXPORT_SYMBOL_GPL(iio_hw_consumer_free);
 
+static void devm_iio_hw_consumer_release(struct device *dev, void *res)
+{
+	iio_hw_consumer_free(*(struct iio_hw_consumer **)res);
+}
+
+static int devm_iio_hw_consumer_match(struct device *dev, void *res, void *data)
+{
+	struct iio_hw_consumer **r = res;
+
+	if (!r || !*r) {
+		WARN_ON(!r || !*r);
+		return 0;
+	}
+	return *r == data;
+}
+
+/**
+ * devm_iio_hw_consumer_alloc - Resource-managed iio_hw_consumer_alloc()
+ * @dev: Pointer to consumer device.
+ *
+ * Managed iio_hw_consumer_alloc. iio_hw_consumer allocated with this function
+ * is automatically freed on driver detach.
+ *
+ * If an iio_hw_consumer allocated with this function needs to be freed
+ * separately, devm_iio_hw_consumer_free() must be used.
+ *
+ * returns pointer to allocated iio_hw_consumer on success, NULL on failure.
+ */
+struct iio_hw_consumer *devm_iio_hw_consumer_alloc(struct device *dev)
+{
+	struct iio_hw_consumer **ptr, *iio_hwc;
+
+	ptr = devres_alloc(devm_iio_hw_consumer_release, sizeof(*ptr),
+			   GFP_KERNEL);
+	if (!ptr)
+		return NULL;
+
+	iio_hwc = iio_hw_consumer_alloc(dev);
+	if (IS_ERR(iio_hwc)) {
+		devres_free(ptr);
+	} else {
+		*ptr = iio_hwc;
+		devres_add(dev, ptr);
+	}
+
+	return iio_hwc;
+}
+EXPORT_SYMBOL_GPL(devm_iio_hw_consumer_alloc);
+
+/**
+ * devm_iio_hw_consumer_free - Resource-managed iio_hw_consumer_free()
+ * @dev: Pointer to consumer device.
+ * @hwc: iio_hw_consumer to free.
+ *
+ * Free iio_hw_consumer allocated with devm_iio_hw_consumer_alloc().
+ */
+void devm_iio_hw_consumer_free(struct device *dev, struct iio_hw_consumer *hwc)
+{
+	int rc;
+
+	rc = devres_release(dev, devm_iio_hw_consumer_release,
+			    devm_iio_hw_consumer_match, hwc);
+	WARN_ON(rc);
+}
+EXPORT_SYMBOL_GPL(devm_iio_hw_consumer_free);
+
 /**
  * iio_hw_consumer_enable() - Enable IIO hardware consumer
  * @hwc: iio_hw_consumer to enable.
diff --git a/include/linux/iio/hw-consumer.h b/include/linux/iio/hw-consumer.h
index db8c00b..44d48bb 100644
--- a/include/linux/iio/hw-consumer.h
+++ b/include/linux/iio/hw-consumer.h
@@ -13,6 +13,8 @@ struct iio_hw_consumer;
 
 struct iio_hw_consumer *iio_hw_consumer_alloc(struct device *dev);
 void iio_hw_consumer_free(struct iio_hw_consumer *hwc);
+struct iio_hw_consumer *devm_iio_hw_consumer_alloc(struct device *dev);
+void devm_iio_hw_consumer_free(struct device *dev, struct iio_hw_consumer *hwc);
 int iio_hw_consumer_enable(struct iio_hw_consumer *hwc);
 void iio_hw_consumer_disable(struct iio_hw_consumer *hwc);
 
-- 
2.7.4

^ 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