Linux-ARM-Kernel Archive on lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v9 3/3] arm64: kexec_file: add rng-seed support
From: Hsin-Yi Wang @ 2019-08-22  7:15 UTC (permalink / raw)
  To: linux-arm-kernel, Theodore Y . Ts'o
  Cc: Kate Stewart, Peter Zijlstra, Catalin Marinas, Mukesh Ojha,
	Grzegorz Halat, H . Peter Anvin, Guenter Roeck, Will Deacon,
	Marek Szyprowski, Rob Herring, Daniel Thompson, Anders Roxell,
	Yury Norov, Marc Zyngier, Russell King, Aaro Koskinen,
	Ingo Molnar, Viresh Kumar, Waiman Long, Paul E . McKenney, Wei Li,
	Alexey Dobriyan, Julien Thierry, Len Brown, Kees Cook,
	Arnd Bergmann, Rik van Riel, Stephen Boyd, Shaokun Zhang,
	Mike Rapoport, Borislav Petkov, Josh Poimboeuf, Thomas Gleixner,
	Greg Kroah-Hartman, Marcelo Tosatti, linux-kernel, Armijn Hemel,
	Jiri Kosina, Mathieu Desnoyers, Andrew Morton, Tim Chen,
	David S . Miller
In-Reply-To: <20190822071522.143986-1-hsinyi@chromium.org>

Adding "rng-seed" to dtb. It's fine to add this property if original
fdt doesn't contain it. Since original seed will be wiped after
read, so use a default size 128 bytes here.

Signed-off-by: Hsin-Yi Wang <hsinyi@chromium.org>
Reviewed-by: Stephen Boyd <swboyd@chromium.org>
---
No change since v7.
---
 arch/arm64/kernel/machine_kexec_file.c | 18 +++++++++++++++++-
 1 file changed, 17 insertions(+), 1 deletion(-)

diff --git a/arch/arm64/kernel/machine_kexec_file.c b/arch/arm64/kernel/machine_kexec_file.c
index ba78ee7ca990..7b08bf9499b6 100644
--- a/arch/arm64/kernel/machine_kexec_file.c
+++ b/arch/arm64/kernel/machine_kexec_file.c
@@ -27,6 +27,8 @@
 #define FDT_PROP_INITRD_END	"linux,initrd-end"
 #define FDT_PROP_BOOTARGS	"bootargs"
 #define FDT_PROP_KASLR_SEED	"kaslr-seed"
+#define FDT_PROP_RNG_SEED	"rng-seed"
+#define RNG_SEED_SIZE		128
 
 const struct kexec_file_ops * const kexec_file_loaders[] = {
 	&kexec_image_ops,
@@ -102,6 +104,19 @@ static int setup_dtb(struct kimage *image,
 				FDT_PROP_KASLR_SEED);
 	}
 
+	/* add rng-seed */
+	if (rng_is_initialized()) {
+		u8 rng_seed[RNG_SEED_SIZE];
+		get_random_bytes(rng_seed, RNG_SEED_SIZE);
+		ret = fdt_setprop(dtb, off, FDT_PROP_RNG_SEED, rng_seed,
+				RNG_SEED_SIZE);
+		if (ret)
+			goto out;
+	} else {
+		pr_notice("RNG is not initialised: omitting \"%s\" property\n",
+				FDT_PROP_RNG_SEED);
+	}
+
 out:
 	if (ret)
 		return (ret == -FDT_ERR_NOSPACE) ? -ENOMEM : -EINVAL;
@@ -110,7 +125,8 @@ static int setup_dtb(struct kimage *image,
 }
 
 /*
- * More space needed so that we can add initrd, bootargs and kaslr-seed.
+ * More space needed so that we can add initrd, bootargs, kaslr-seed, and
+ * rng-seed.
  */
 #define DTB_EXTRA_SPACE 0x1000
 
-- 
2.20.1


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply related

* RE: perf tool issue following 'perf stat: Fix --no-scale' patch integration
From: Gerald BAEZA @ 2019-08-22  7:17 UTC (permalink / raw)
  To: acme@kernel.org, Andi Kleen, linux-arm-kernel@lists.infradead.org,
	linux-kernel@vger.kernel.org
  Cc: Alexandre TORGUE, mathieu.poirier@linaro.org,
	suzuki.poulose@arm.com, peterz@infradead.org,
	alexander.shishkin@linux.intel.com, mingo@redhat.com,
	namhyung@kernel.org, jolsa@redhat.com
In-Reply-To: <20190821195451.GG3929@kernel.org>

Hello Arnaldo and Andi

Indeed, 'aligned(8)' instead of 'aligned(64)'.
Thanks for your quick feedbacks and I am going to prepare the patch.

Gérald
 


> Em Wed, Aug 21, 2019 at 09:26:35AM -0700, Andi Kleen escreveu:
> > >
> > >    +             char contents[] __attribute__((aligned(64)));
> >
> > I think you want aligned(8). The parameter is bytes, not bits.
> >
> > >
> > >
> > >    But the xyarray structure is generic so I think this patch cannot be the
> > >    final one.
> >
> > I think it's fine actually to just apply this generically (with 8). It
> > will only waste a few bytes on other 32bit architectures and should be
> > a nop on 64bit, not worth doing anything more sophisticated.
> >
> > I would just submit a patch to do that.
> 
> Agreed.
> 
> - Arnaldo

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply

* Re: [PATCH] soc: imx: gpcv2: Print the correct error code
From: Daniel Baluta @ 2019-08-22  8:12 UTC (permalink / raw)
  To: dl-linux-imx, linux-kernel@vger.kernel.org, festevam@gmail.com,
	agx@sigxcpu.org, robh@kernel.org, shawnguo@kernel.org,
	andrew.smirnov@gmail.com, Anson Huang,
	linux-arm-kernel@lists.infradead.org, l.stach@pengutronix.de,
	kernel@pengutronix.de, s.hauer@pengutronix.de
In-Reply-To: <ceab1bb4984d0a4f59a580cd9956c1fd6d6a78f3.1566405120.git.agx@sigxcpu.org>

On Wed, 2019-08-21 at 18:33 +0200, Guido Günther wrote:
> The current code prints 'ret' (thus 0) while it should use 'err'.
> 
> Signed-off-by: Guido Günther <agx@sigxcpu.org>

Reviewed-by: Daniel Baluta <daniel.baluta@nxp.com>

> ---
>  drivers/soc/imx/gpcv2.c | 2 +-
>  1 file changed, 1 insertion(+), 1 deletion(-)
> 
> diff --git a/drivers/soc/imx/gpcv2.c b/drivers/soc/imx/gpcv2.c
> index 31b8d002d855..b0dffb06c05d 100644
> --- a/drivers/soc/imx/gpcv2.c
> +++ b/drivers/soc/imx/gpcv2.c
> @@ -198,7 +198,7 @@ static int imx_gpc_pu_pgc_sw_pxx_req(struct
> generic_pm_domain *genpd,
>  		err = regulator_disable(domain->regulator);
>  		if (err)
>  			dev_err(domain->dev,
> -				"failed to disable regulator: %d\n",
> ret);
> +				"failed to disable regulator: %d\n",
> err);
>  		/* Preserve earlier error code */
>  		ret = ret ?: err;
>  	}
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply

* Re: [PATCH 02/19] dt-bindings: arm: mrvl: Document MMP3 compatible string
From: Lubomir Rintel @ 2019-08-22  8:12 UTC (permalink / raw)
  To: Rob Herring
  Cc: Mark Rutland, devicetree, Jason Cooper, Stephen Boyd,
	Marc Zyngier, Michael Turquette, Russell King,
	Kishon Vijay Abraham I, linux-arm-kernel, Olof Johansson,
	Thomas Gleixner, linux-clk, linux-kernel
In-Reply-To: <20190821210349.GA29732@bogus>

On Wed, 2019-08-21 at 16:03 -0500, Rob Herring wrote:
> On Fri, Aug 09, 2019 at 11:31:41AM +0200, Lubomir Rintel wrote:
> > Marvel MMP3 is a successor to MMP2, containing similar peripherals with two
> > PJ4B cores.
> > 
> > Signed-off-by: Lubomir Rintel <lkundrak@v3.sk>
> > ---
> >  Documentation/devicetree/bindings/arm/mrvl/mrvl.txt | 4 ++++
> >  1 file changed, 4 insertions(+)
> > 
> > diff --git a/Documentation/devicetree/bindings/arm/mrvl/mrvl.txt b/Documentation/devicetree/bindings/arm/mrvl/mrvl.txt
> > index 951687528efb0..66e1e1414245b 100644
> > --- a/Documentation/devicetree/bindings/arm/mrvl/mrvl.txt
> > +++ b/Documentation/devicetree/bindings/arm/mrvl/mrvl.txt
> > @@ -12,3 +12,7 @@ Required root node properties:
> >  MMP2 Brownstone Board
> >  Required root node properties:
> >  	- compatible = "mrvl,mmp2-brownstone", "mrvl,mmp2";
> > +
> > +MMP3 SoC
> > +Required root node properties:
> > +	- compatible = "marvell,mmp3";
> 
> Please convert this file to DT schema before adding new SoCs.

Is this something that should generally be done for all new or changed
DT bindings?

> 
> Rob

Thanks
Lubo


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply

* Re: [PATCH 1/4] misc: xilinx_sdfec: Fix a couple small information leaks
From: Michal Simek @ 2019-08-22  8:14 UTC (permalink / raw)
  To: Dan Carpenter, Derek Kiernan, Dragan Cvetic
  Cc: Arnd Bergmann, Greg Kroah-Hartman, kernel-janitors, Michal Simek,
	linux-kernel, linux-arm-kernel
In-Reply-To: <20190821070606.GA26957@mwanda>

Hi Dan,

On 21. 08. 19 9:06, Dan Carpenter wrote:
> These structs have holes in them so we end up disclosing a few bytes of
> uninitialized stack data.
> 
> drivers/misc/xilinx_sdfec.c:305 xsdfec_get_status() warn: check that 'status' doesn't leak information (struct has a hole after 'activity')
> drivers/misc/xilinx_sdfec.c:449 xsdfec_get_turbo() warn: check that 'turbo_params' doesn't leak information (struct has a hole after 'scale')

Who is generating these warnings? Is this any new GCC or different tool?
I see that 3byte padding but never seen these warnings.

> We need to zero out the holes with memset().
> 
> Fixes: 6bd6a690c2e7 ("misc: xilinx_sdfec: Add stats & status ioctls")
> Signed-off-by: Dan Carpenter <dan.carpenter@oracle.com>
> ---
>  drivers/misc/xilinx_sdfec.c | 2 ++
>  1 file changed, 2 insertions(+)
> 
> diff --git a/drivers/misc/xilinx_sdfec.c b/drivers/misc/xilinx_sdfec.c
> index 912e939dec62..dc1b8b412712 100644
> --- a/drivers/misc/xilinx_sdfec.c
> +++ b/drivers/misc/xilinx_sdfec.c
> @@ -295,6 +295,7 @@ static int xsdfec_get_status(struct xsdfec_dev *xsdfec, void __user *arg)
>  	struct xsdfec_status status;
>  	int err;
>  
> +	memset(&status, 0, sizeof(status));
>  	spin_lock_irqsave(&xsdfec->error_data_lock, xsdfec->flags);
>  	status.state = xsdfec->state;
>  	xsdfec->state_updated = false;
> @@ -440,6 +441,7 @@ static int xsdfec_get_turbo(struct xsdfec_dev *xsdfec, void __user *arg)
>  	if (xsdfec->config.code == XSDFEC_LDPC_CODE)
>  		return -EIO;
>  
> +	memset(&turbo_params, 0, sizeof(turbo_params));
>  	reg_value = xsdfec_regread(xsdfec, XSDFEC_TURBO_ADDR);
>  
>  	turbo_params.scale = (reg_value & XSDFEC_TURBO_SCALE_MASK) >>
> 

Reviewed-by: Michal Simek <michal.simek@xilinx.com>

Thanks,
Michal

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply

* Re: [PATCH 2/4] misc: xilinx_sdfec: Return -EFAULT if copy_from_user() fails
From: Michal Simek @ 2019-08-22  8:16 UTC (permalink / raw)
  To: Dan Carpenter, Derek Kiernan, Dragan Cvetic
  Cc: Arnd Bergmann, Greg Kroah-Hartman, kernel-janitors, Michal Simek,
	linux-kernel, linux-arm-kernel
In-Reply-To: <20190821070702.GB26957@mwanda>

On 21. 08. 19 9:07, Dan Carpenter wrote:
> The copy_from_user() funciton returns the number of bytes remaining to

typo here.

> be copied but we want to return -EFAULT to the user.
> 
> Fixes: 20ec628e8007 ("misc: xilinx_sdfec: Add ability to configure LDPC")
> Signed-off-by: Dan Carpenter <dan.carpenter@oracle.com>
> ---
>  drivers/misc/xilinx_sdfec.c | 5 +++--
>  1 file changed, 3 insertions(+), 2 deletions(-)
> 
> diff --git a/drivers/misc/xilinx_sdfec.c b/drivers/misc/xilinx_sdfec.c
> index dc1b8b412712..813b82c59360 100644
> --- a/drivers/misc/xilinx_sdfec.c
> +++ b/drivers/misc/xilinx_sdfec.c
> @@ -651,9 +651,10 @@ static int xsdfec_add_ldpc(struct xsdfec_dev *xsdfec, void __user *arg)
>  	if (!ldpc)
>  		return -ENOMEM;
>  
> -	ret = copy_from_user(ldpc, arg, sizeof(*ldpc));
> -	if (ret)
> +	if (copy_from_user(ldpc, arg, sizeof(*ldpc))) {
> +		ret = -EFAULT;
>  		goto err_out;
> +	}
>  
>  	if (xsdfec->config.code == XSDFEC_TURBO_CODE) {
>  		ret = -EIO;
> 

When typo fixed feel free to add my
Reviewed-by: Michal Simek <michal.simek@xilinx.com>

Thanks,
Michal

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply

* Re: [PATCH 3/4] misc: xilinx_sdfec: Prevent a divide by zero in xsdfec_reg0_write()
From: Michal Simek @ 2019-08-22  8:18 UTC (permalink / raw)
  To: Dan Carpenter, Derek Kiernan, Dragan Cvetic
  Cc: Arnd Bergmann, Greg Kroah-Hartman, kernel-janitors, Michal Simek,
	linux-kernel, linux-arm-kernel
In-Reply-To: <20190821070953.GC26957@mwanda>

On 21. 08. 19 9:09, Dan Carpenter wrote:
> The "psize" value comes from the user so we need to verify that it's
> non-zero before we check if "n % psize" or it will crash.
> 
> Fixes: 20ec628e8007 ("misc: xilinx_sdfec: Add ability to configure LDPC")
> Signed-off-by: Dan Carpenter <dan.carpenter@oracle.com>
> ---
> The parentheses in this condition are a no-op.  They're just confusing.
> Perhaps something else was intended?
> 
>  drivers/misc/xilinx_sdfec.c | 2 +-
>  1 file changed, 1 insertion(+), 1 deletion(-)
> 
> diff --git a/drivers/misc/xilinx_sdfec.c b/drivers/misc/xilinx_sdfec.c
> index 813b82c59360..3fc53d20abf3 100644
> --- a/drivers/misc/xilinx_sdfec.c
> +++ b/drivers/misc/xilinx_sdfec.c
> @@ -460,7 +460,7 @@ static int xsdfec_reg0_write(struct xsdfec_dev *xsdfec, u32 n, u32 k, u32 psize,
>  {
>  	u32 wdata;
>  
> -	if (n < XSDFEC_REG0_N_MIN || n > XSDFEC_REG0_N_MAX ||
> +	if (n < XSDFEC_REG0_N_MIN || n > XSDFEC_REG0_N_MAX || psize == 0 ||
>  	    (n > XSDFEC_REG0_N_MUL_P * psize) || n <= k || ((n % psize) != 0)) {
>  		dev_dbg(xsdfec->dev, "N value is not in range");
>  		return -EINVAL;
> 

Reviewed-by: Michal Simek <michal.simek@xilinx.com>

Thanks,
Michal

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply

* Re: [PATCH] clk: imx: pll14xx: avoid glitch when set rate
From: Leonard Crestez @ 2019-08-22  8:20 UTC (permalink / raw)
  To: Peng Fan, sboyd@kernel.org, Jacky Bai
  Cc: Abel Vesa, Anson Huang, shawnguo@kernel.org,
	mturquette@baylibre.com, linux-kernel@vger.kernel.org,
	linux-clk@vger.kernel.org, dl-linux-imx, kernel@pengutronix.de,
	festevam@gmail.com, s.hauer@pengutronix.de,
	linux-arm-kernel@lists.infradead.org
In-Reply-To: <1566266337-21597-1-git-send-email-peng.fan@nxp.com>

On 20.08.2019 05:17, Peng Fan wrote:
> According to PLL1443XA and PLL1416X spec,
> "When BYPASS is 0 and RESETB is changed from 0 to 1, FOUT starts to
> output unstable clock until lock time passes. PLL1416X/PLL1443XA may
> generate a glitch at FOUT."
> 
> So set BYPASS when RESETB is changed from 0 to 1 to avoid glitch.
> In the end of set rate, BYPASS will be cleared.
> 
> @@ -191,6 +191,10 @@ static int clk_pll1416x_set_rate(struct clk_hw *hw, unsigned long drate,
>   	tmp &= ~RST_MASK;
>   	writel_relaxed(tmp, pll->base);
>   
> +	/* Enable BYPASS */
> +	tmp |= BYPASS_MASK;
> +	writel(tmp, pll->base);
> +

Shouldn't BYPASS be set before reset?

Also, isn't a similar bypass/unbypass dance also needed in 
clk_pll14xx_prepare? As far as I understand that could also output 
glitches until the PLL is locked. It could be a separate patch.

It's strange that this BYPASS bit is also handled by muxes like 
audio_pll1_bypass in clk-imx8mm.c but that's a separate issue not 
strictly related to the glitches you're trying to fix here.

--
Regards,
Leonard

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply

* [PATCH v8 0/5] media: Allwinner A10 CSI support
From: Maxime Ripard @ 2019-08-22  8:21 UTC (permalink / raw)
  To: Hans Verkuil, Sakari Ailus, Mauro Carvalho Chehab
  Cc: Mark Rutland, devicetree, Maxime Ripard, linux-kernel,
	Chen-Yu Tsai, Rob Herring, Laurent Pinchart, Thomas Petazzoni,
	Frank Rowand, linux-arm-kernel, linux-media

From: Maxime Ripard <maxime.ripard@bootlin.com>

Hi,

Here is a series introducing the support for the A10 (and SoCs of the same
generation) CMOS Sensor Interface (called CSI, not to be confused with
MIPI-CSI, which isn't support by that IP).

That interface is pretty straightforward, but the driver has a few issues
that I wanted to bring up:

  * The only board I've been testing this with has an ov5640 sensor
    attached, which doesn't work with the upstream driver. Copying the
    Allwinner init sequence works though, and this is how it has been
    tested. Testing with a second sensor would allow to see if it's an
    issue on the CSI side or the sensor side.
  * We don't have support for the ISP at the moment, but this can be added
    eventually.

Here is the v4l2-compliance output (commit f61132e81d79 of v4l-utils)
v4l2-compliance SHA: not available, 32 bits

Compliance test for device /dev/video1:

Driver Info:
	Driver name      : sun4i_csi
	Card type        : sun4i-csi
	Bus info         : platform:1c09000.csi
	Driver version   : 5.3.0
	Capabilities     : 0x84201000
		Video Capture Multiplanar
		Streaming
		Extended Pix Format
		Device Capabilities
	Device Caps      : 0x04201000
		Video Capture Multiplanar
		Streaming
		Extended Pix Format
Media Driver Info:
	Driver name      : sun4i-csi
	Model            : Allwinner Video Capture Device
	Serial           :
	Bus info         :
	Media version    : 5.3.0
	Hardware revision: 0x00000000 (0)
	Driver version   : 5.3.0
Interface Info:
	ID               : 0x03000008
	Type             : V4L Video
Entity Info:
	ID               : 0x00000006 (6)
	Name             : sun4i_csi
	Function         : V4L2 I/O
	Pad 0x01000007   : 0: Sink, Must Connect
	  Link 0x0200000a: from remote pad 0x1000005 of entity 'sun4i-csi-0': Data, Enabled, Immutable

Required ioctls:
	test MC information (see 'Media Driver Info' above): OK
	test VIDIOC_QUERYCAP: OK

Allow for multiple opens:
	test second /dev/video1 open: OK
	test VIDIOC_QUERYCAP: OK
	test VIDIOC_G/S_PRIORITY: OK
	test for unlimited opens: OK

Debug ioctls:
	test VIDIOC_DBG_G/S_REGISTER: OK (Not Supported)
	test VIDIOC_LOG_STATUS: OK (Not Supported)

Input ioctls:
	test VIDIOC_G/S_TUNER/ENUM_FREQ_BANDS: OK (Not Supported)
	test VIDIOC_G/S_FREQUENCY: OK (Not Supported)
	test VIDIOC_S_HW_FREQ_SEEK: OK (Not Supported)
	test VIDIOC_ENUMAUDIO: OK (Not Supported)
	test VIDIOC_G/S/ENUMINPUT: OK
	test VIDIOC_G/S_AUDIO: OK (Not Supported)
	Inputs: 1 Audio Inputs: 0 Tuners: 0

Output ioctls:
	test VIDIOC_G/S_MODULATOR: OK (Not Supported)
	test VIDIOC_G/S_FREQUENCY: OK (Not Supported)
	test VIDIOC_ENUMAUDOUT: OK (Not Supported)
	test VIDIOC_G/S/ENUMOUTPUT: OK (Not Supported)
	test VIDIOC_G/S_AUDOUT: OK (Not Supported)
	Outputs: 0 Audio Outputs: 0 Modulators: 0

Input/Output configuration ioctls:
	test VIDIOC_ENUM/G/S/QUERY_STD: OK (Not Supported)
	test VIDIOC_ENUM/G/S/QUERY_DV_TIMINGS: OK (Not Supported)
	test VIDIOC_DV_TIMINGS_CAP: OK (Not Supported)
	test VIDIOC_G/S_EDID: OK (Not Supported)

Control ioctls (Input 0):
	test VIDIOC_QUERY_EXT_CTRL/QUERYMENU: OK (Not Supported)
	test VIDIOC_QUERYCTRL: OK (Not Supported)
	test VIDIOC_G/S_CTRL: OK (Not Supported)
	test VIDIOC_G/S/TRY_EXT_CTRLS: OK (Not Supported)
	test VIDIOC_(UN)SUBSCRIBE_EVENT/DQEVENT: OK (Not Supported)
	test VIDIOC_G/S_JPEGCOMP: OK (Not Supported)
	Standard Controls: 0 Private Controls: 0

Format ioctls (Input 0):
	test VIDIOC_ENUM_FMT/FRAMESIZES/FRAMEINTERVALS: OK
	test VIDIOC_G/S_PARM: OK (Not Supported)
	test VIDIOC_G_FBUF: OK (Not Supported)
	test VIDIOC_G_FMT: OK
	test VIDIOC_TRY_FMT: OK
	test VIDIOC_S_FMT: OK
	test VIDIOC_G_SLICED_VBI_CAP: OK (Not Supported)
	test Cropping: OK (Not Supported)
	test Composing: OK (Not Supported)
	test Scaling: OK

Codec ioctls (Input 0):
	test VIDIOC_(TRY_)ENCODER_CMD: OK (Not Supported)
	test VIDIOC_G_ENC_INDEX: OK (Not Supported)
	test VIDIOC_(TRY_)DECODER_CMD: OK (Not Supported)

Buffer ioctls (Input 0):
	test VIDIOC_REQBUFS/CREATE_BUFS/QUERYBUF: OK
	test VIDIOC_EXPBUF: OK

Test input 0:

Streaming ioctls:
	test read/write: OK (Not Supported)
	test blocking wait: OK
	test MMAP: OK
	test USERPTR: OK (Not Supported)
	test DMABUF: OK (Not Supported)

Total: 49, Succeeded: 49, Failed: 0, Warnings: 0

media-ctl -p -d /dev/media1 output after boot:
Media controller API version 5.3.0

Media device information
------------------------
driver          sun4i-csi
model           Allwinner Video Capture Device
serial
bus info
hw revision     0x0
driver version  5.3.0

Device topology
- entity 1: ov5640 1-0021 (1 pad, 1 link)
            type V4L2 subdev subtype Sensor flags 0
            device node name /dev/v4l-subdev0
	pad0: Source
		[fmt:YUYV8_2X8/640x480@1/30 field:none colorspace:srgb xfer:srgb ycbcr:601 quantization:full-range]
		-> "sun4i-csi-0":0 [ENABLED,IMMUTABLE]

- entity 3: sun4i-csi-0 (2 pads, 2 links)
            type V4L2 subdev subtype Unknown flags 0
            device node name /dev/v4l-subdev1
	pad0: Sink
		[fmt:YUYV8_2X8/640x480 field:none colorspace:raw]
		<- "ov5640 1-0021":0 [ENABLED,IMMUTABLE]
	pad1: Source
		[fmt:YUYV8_2X8/640x480 field:none colorspace:raw]
		-> "sun4i_csi":0 [ENABLED,IMMUTABLE]

- entity 6: sun4i_csi (1 pad, 1 link)
            type Node subtype V4L flags 0
            device node name /dev/video1
	pad0: Sink
		<- "sun4i-csi-0":1 [ENABLED,IMMUTABLE]

Let me know what you think,
Maxime

Changes from v7:
  - Add a comment refering to video-interfaces.txt to the binding
  - Rework the error path of registration
  - Fix 80 chars issue on a function
  - Add the 16bits width option to the dt binding
  - Remove out label in the interrupt handler and just return
  - Just compute the next buffer in buffer_flip, instead of going through
    the current buffer.
  - Fix indentation
  - Convert to v4l2_fwnode_endpoint_parse /
    v4l2_async_notifier_add_fwnode_remote_subdev

Changes from v6:
  - Add init_cfg callback on the pads
  - Use v4l2_subdev_link_validate instead of hand-rolled link validate
  - Make sun4i_csi_qops const
  - Add MODULE_DESCRIPTION, MODULE_AUTHOR and MODULE_LICENSE
  - Remove the mod clock handling from the CSI driver
  - Remove the A10 compatible fallback
  - Rework the CSI pinctrl groups
  - Add an example to the binding

Changes from v5:
  - Add link_validate/get_fmt/set_fmt/enum_mbus_code to the subdevice
  - Create a device file for the subdevice
  - Add link_validate to the video device
  - Remove the storage of both the v4l2_pix_format_mplane structure and the
    sun4i_csi_format structure, since the latter can be retrieved easily
    from the former, and this is actually needed in a single place.
  - Fix the copyright year notice

Changes from v4:
  - Created an intermediate sub-device

Changes from v3:
  - Rebased on v5.1-rc
  - Fixed the YAML binding according to Rob's review

Changes from v2:
  - Address a few minors comments on the error path, the return type of
    some functions, the type of some variables
  - Disable the device if the subdev call fails in start_streaming
  - Use __maybe_unused and SET_RUNTIME_PM_OPS for the runtime PM hooks
  - Call media_device_cleanup in the remove function
  - Add a dependency on the subdev API and the common clock framework
  - Fix the MAINTAINERS entry to point to the yaml file
  - Add the of graph bindings to the YAML schemas
  - Rebase on next

Changes from v1:
  - Make sure it's compliant with a much newer v4l2-compliance
  - Conversion of the DT bindings to a JSON schema
  - Drop the vendor properties and use a separate compatible instead
  - Fix an issue on the last frame where we would not have any buffer
    queued and would report an error by using a scratch buffer
  - Fix the warnings reported by v4l2-compliance
  - Rebase on top of 5.0-rc1
  - Added a MAINTAINERS entry
  - Switched to strscpy
  - Fixed SPDX header

Maxime Ripard (5):
  dt-bindings: media: Add Allwinner A10 CSI binding
  media: sunxi: Refactor the Makefile and Kconfig
  media: sunxi: Add A10 CSI driver
  ARM: dts: sun7i: Add CSI0 controller
  DO NOT MERGE: ARM: dts: bananapi: Add Camera support

 Documentation/devicetree/bindings/media/allwinner,sun4i-a10-csi.yaml | 107 +++++++++++++++++-
 MAINTAINERS                                                          |   8 +-
 arch/arm/boot/dts/sun7i-a20-bananapi.dts                             |  87 ++++++++++++++-
 arch/arm/boot/dts/sun7i-a20.dtsi                                     |  25 ++++-
 drivers/media/platform/Kconfig                                       |   2 +-
 drivers/media/platform/Makefile                                      |   2 +-
 drivers/media/platform/sunxi/Kconfig                                 |   2 +-
 drivers/media/platform/sunxi/Makefile                                |   2 +-
 drivers/media/platform/sunxi/sun4i-csi/Kconfig                       |  11 ++-
 drivers/media/platform/sunxi/sun4i-csi/Makefile                      |   5 +-
 drivers/media/platform/sunxi/sun4i-csi/sun4i_csi.c                   | 312 ++++++++++++++++++++++++++++++++++++++++++++++++++-
 drivers/media/platform/sunxi/sun4i-csi/sun4i_csi.h                   | 160 +++++++++++++++++++++++++-
 drivers/media/platform/sunxi/sun4i-csi/sun4i_dma.c                   | 453 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
 drivers/media/platform/sunxi/sun4i-csi/sun4i_v4l2.c                  | 385 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
 14 files changed, 1559 insertions(+), 2 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/media/allwinner,sun4i-a10-csi.yaml
 create mode 100644 drivers/media/platform/sunxi/Kconfig
 create mode 100644 drivers/media/platform/sunxi/Makefile
 create mode 100644 drivers/media/platform/sunxi/sun4i-csi/Kconfig
 create mode 100644 drivers/media/platform/sunxi/sun4i-csi/Makefile
 create mode 100644 drivers/media/platform/sunxi/sun4i-csi/sun4i_csi.c
 create mode 100644 drivers/media/platform/sunxi/sun4i-csi/sun4i_csi.h
 create mode 100644 drivers/media/platform/sunxi/sun4i-csi/sun4i_dma.c
 create mode 100644 drivers/media/platform/sunxi/sun4i-csi/sun4i_v4l2.c

base-commit: 85b8819be27eab140d280bbee4f01385beb11e7d
-- 
git-series 0.9.1

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply

* [PATCH v8 1/5] dt-bindings: media: Add Allwinner A10 CSI binding
From: Maxime Ripard @ 2019-08-22  8:21 UTC (permalink / raw)
  To: Hans Verkuil, Sakari Ailus, Mauro Carvalho Chehab
  Cc: Mark Rutland, devicetree, Rob Herring, Maxime Ripard,
	linux-kernel, Chen-Yu Tsai, Rob Herring, Laurent Pinchart,
	Thomas Petazzoni, Frank Rowand, linux-arm-kernel, linux-media
In-Reply-To: <cover.85d78dd1a3b44fe4cde1b65a9b1eb3b95daea7cc.1566462064.git-series.maxime.ripard@bootlin.com>

From: Maxime Ripard <maxime.ripard@bootlin.com>

The Allwinner A10 CMOS Sensor Interface is a camera capture interface also
used in later (A10s, A13, A20, R8 and GR8) SoCs.

On some SoCs, like the A10, there's multiple instances of that controller,
with one instance supporting more channels and having an ISP.

Reviewed-by: Rob Herring <robh@kernel.org>
Signed-off-by: Maxime Ripard <maxime.ripard@bootlin.com>
---
 Documentation/devicetree/bindings/media/allwinner,sun4i-a10-csi.yaml | 107 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
 MAINTAINERS                                                          |   7 +++++-
 2 files changed, 114 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/media/allwinner,sun4i-a10-csi.yaml

diff --git a/Documentation/devicetree/bindings/media/allwinner,sun4i-a10-csi.yaml b/Documentation/devicetree/bindings/media/allwinner,sun4i-a10-csi.yaml
new file mode 100644
index 000000000000..c994a4092a4f
--- /dev/null
+++ b/Documentation/devicetree/bindings/media/allwinner,sun4i-a10-csi.yaml
@@ -0,0 +1,107 @@
+# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/arm/allwinner,sun4i-a10-csi.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Allwinner A10 CMOS Sensor Interface (CSI) Device Tree Bindings
+
+maintainers:
+  - Chen-Yu Tsai <wens@csie.org>
+  - Maxime Ripard <maxime.ripard@bootlin.com>
+
+description: |-
+  The Allwinner A10 and later has a CMOS Sensor Interface to retrieve
+  frames from a parallel or BT656 sensor.
+
+properties:
+  compatible:
+    const: allwinner,sun7i-a20-csi0
+
+  reg:
+    maxItems: 1
+
+  interrupts:
+    maxItems: 1
+
+  clocks:
+    items:
+      - description: The CSI interface clock
+      - description: The CSI module clock
+      - description: The CSI ISP clock
+      - description: The CSI DRAM clock
+
+  clock-names:
+    items:
+      - const: bus
+      - const: mod
+      - const: isp
+      - const: ram
+
+  resets:
+    maxItems: 1
+
+  # See ./video-interfaces.txt for details
+  port:
+    type: object
+    additionalProperties: false
+
+    properties:
+      endpoint:
+        properties:
+          bus-width:
+            enum: [8, 16]
+
+          data-active: true
+          hsync-active: true
+          pclk-sample: true
+          remote-endpoint: true
+          vsync-active: true
+
+        required:
+          - bus-width
+          - data-active
+          - hsync-active
+          - pclk-sample
+          - remote-endpoint
+          - vsync-active
+
+    required:
+      - endpoint
+
+required:
+  - compatible
+  - reg
+  - interrupts
+  - clocks
+
+additionalProperties: false
+
+examples:
+  - |
+    #include <dt-bindings/interrupt-controller/arm-gic.h>
+    #include <dt-bindings/clock/sun7i-a20-ccu.h>
+    #include <dt-bindings/reset/sun4i-a10-ccu.h>
+
+    csi0: csi@1c09000 {
+        compatible = "allwinner,sun7i-a20-csi0";
+        reg = <0x01c09000 0x1000>;
+        interrupts = <GIC_SPI 42 IRQ_TYPE_LEVEL_HIGH>;
+        clocks = <&ccu CLK_AHB_CSI0>, <&ccu CLK_CSI0>,
+                 <&ccu CLK_CSI_SCLK>, <&ccu CLK_DRAM_CSI0>;
+        clock-names = "bus", "mod", "isp", "ram";
+        resets = <&ccu RST_CSI0>;
+
+        port {
+            csi_from_ov5640: endpoint {
+                remote-endpoint = <&ov5640_to_csi>;
+                bus-width = <8>;
+                hsync-active = <1>; /* Active high */
+                vsync-active = <0>; /* Active low */
+                data-active = <1>;  /* Active high */
+                pclk-sample = <1>;  /* Rising */
+            };
+        };
+    };
+
+...
diff --git a/MAINTAINERS b/MAINTAINERS
index 30bf852e6d6b..65af586defcc 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -1420,6 +1420,13 @@ F:	drivers/pinctrl/sunxi/
 F:	drivers/soc/sunxi/
 T:	git git://git.kernel.org/pub/scm/linux/kernel/git/sunxi/linux.git
 
+Allwinner A10 CSI driver
+M:	Maxime Ripard <mripard@kernel.org>
+L:	linux-media@vger.kernel.org
+T:	git git://linuxtv.org/media_tree.git
+F:	Documentation/devicetree/bindings/media/allwinner,sun4i-a10-csi.yaml
+S:	Maintained
+
 ARM/Amlogic Meson SoC CLOCK FRAMEWORK
 M:	Neil Armstrong <narmstrong@baylibre.com>
 M:	Jerome Brunet <jbrunet@baylibre.com>
-- 
git-series 0.9.1

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply related

* [PATCH v8 2/5] media: sunxi: Refactor the Makefile and Kconfig
From: Maxime Ripard @ 2019-08-22  8:21 UTC (permalink / raw)
  To: Hans Verkuil, Sakari Ailus, Mauro Carvalho Chehab
  Cc: Mark Rutland, devicetree, Maxime Ripard, linux-kernel,
	Chen-Yu Tsai, Rob Herring, Laurent Pinchart, Thomas Petazzoni,
	Frank Rowand, linux-arm-kernel, linux-media
In-Reply-To: <cover.85d78dd1a3b44fe4cde1b65a9b1eb3b95daea7cc.1566462064.git-series.maxime.ripard@bootlin.com>

From: Maxime Ripard <maxime.ripard@bootlin.com>

The Makefile and Kconfig for the sun6i CSI driver are included in the main
Makefile / KConfig file. Since we're going to add a new CSI driver for an
older chip, and the Cedrus driver eventually, it makes more sense to put
those in our directory.

Signed-off-by: Maxime Ripard <maxime.ripard@bootlin.com>
---
 drivers/media/platform/Kconfig        | 2 +-
 drivers/media/platform/Makefile       | 2 +-
 drivers/media/platform/sunxi/Kconfig  | 1 +
 drivers/media/platform/sunxi/Makefile | 1 +
 4 files changed, 4 insertions(+), 2 deletions(-)
 create mode 100644 drivers/media/platform/sunxi/Kconfig
 create mode 100644 drivers/media/platform/sunxi/Makefile

diff --git a/drivers/media/platform/Kconfig b/drivers/media/platform/Kconfig
index 89555f9a813f..2fda8036d11d 100644
--- a/drivers/media/platform/Kconfig
+++ b/drivers/media/platform/Kconfig
@@ -146,7 +146,7 @@ source "drivers/media/platform/am437x/Kconfig"
 source "drivers/media/platform/xilinx/Kconfig"
 source "drivers/media/platform/rcar-vin/Kconfig"
 source "drivers/media/platform/atmel/Kconfig"
-source "drivers/media/platform/sunxi/sun6i-csi/Kconfig"
+source "drivers/media/platform/sunxi/Kconfig"
 
 config VIDEO_TI_CAL
 	tristate "TI CAL (Camera Adaptation Layer) driver"
diff --git a/drivers/media/platform/Makefile b/drivers/media/platform/Makefile
index 7cbbd925124c..6ee7eb0d36f4 100644
--- a/drivers/media/platform/Makefile
+++ b/drivers/media/platform/Makefile
@@ -100,4 +100,4 @@ obj-y					+= meson/
 
 obj-y					+= cros-ec-cec/
 
-obj-$(CONFIG_VIDEO_SUN6I_CSI)		+= sunxi/sun6i-csi/
+obj-y					+= sunxi/
diff --git a/drivers/media/platform/sunxi/Kconfig b/drivers/media/platform/sunxi/Kconfig
new file mode 100644
index 000000000000..1b6e89cb78b2
--- /dev/null
+++ b/drivers/media/platform/sunxi/Kconfig
@@ -0,0 +1 @@
+source "drivers/media/platform/sunxi/sun6i-csi/Kconfig"
diff --git a/drivers/media/platform/sunxi/Makefile b/drivers/media/platform/sunxi/Makefile
new file mode 100644
index 000000000000..8d06f98500ee
--- /dev/null
+++ b/drivers/media/platform/sunxi/Makefile
@@ -0,0 +1 @@
+obj-y		+= sun6i-csi/
-- 
git-series 0.9.1

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply related

* [PATCH v8 3/5] media: sunxi: Add A10 CSI driver
From: Maxime Ripard @ 2019-08-22  8:21 UTC (permalink / raw)
  To: Hans Verkuil, Sakari Ailus, Mauro Carvalho Chehab
  Cc: Mark Rutland, devicetree, Maxime Ripard, linux-kernel,
	Chen-Yu Tsai, Rob Herring, Laurent Pinchart, Thomas Petazzoni,
	Frank Rowand, linux-arm-kernel, linux-media
In-Reply-To: <cover.85d78dd1a3b44fe4cde1b65a9b1eb3b95daea7cc.1566462064.git-series.maxime.ripard@bootlin.com>

From: Maxime Ripard <maxime.ripard@bootlin.com>

The older CSI drivers have camera capture interface different from the one
in the newer ones.

This IP is pretty simple. Some variants (one controller out of two
instances on some SoCs) have an ISP embedded, but there's no code that make
use of it, so we ignored that part for now.

Signed-off-by: Maxime Ripard <maxime.ripard@bootlin.com>
---
 MAINTAINERS                                         |   1 +-
 drivers/media/platform/sunxi/Kconfig                |   1 +-
 drivers/media/platform/sunxi/Makefile               |   1 +-
 drivers/media/platform/sunxi/sun4i-csi/Kconfig      |  11 +-
 drivers/media/platform/sunxi/sun4i-csi/Makefile     |   5 +-
 drivers/media/platform/sunxi/sun4i-csi/sun4i_csi.c  | 312 +++++++++-
 drivers/media/platform/sunxi/sun4i-csi/sun4i_csi.h  | 160 +++++-
 drivers/media/platform/sunxi/sun4i-csi/sun4i_dma.c  | 453 +++++++++++++-
 drivers/media/platform/sunxi/sun4i-csi/sun4i_v4l2.c | 385 +++++++++++-
 9 files changed, 1329 insertions(+)
 create mode 100644 drivers/media/platform/sunxi/sun4i-csi/Kconfig
 create mode 100644 drivers/media/platform/sunxi/sun4i-csi/Makefile
 create mode 100644 drivers/media/platform/sunxi/sun4i-csi/sun4i_csi.c
 create mode 100644 drivers/media/platform/sunxi/sun4i-csi/sun4i_csi.h
 create mode 100644 drivers/media/platform/sunxi/sun4i-csi/sun4i_dma.c
 create mode 100644 drivers/media/platform/sunxi/sun4i-csi/sun4i_v4l2.c

diff --git a/MAINTAINERS b/MAINTAINERS
index 65af586defcc..1cdc7fc20ad9 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -1424,6 +1424,7 @@ Allwinner A10 CSI driver
 M:	Maxime Ripard <mripard@kernel.org>
 L:	linux-media@vger.kernel.org
 T:	git git://linuxtv.org/media_tree.git
+F:	drivers/media/platform/sunxi/sun4i-csi/
 F:	Documentation/devicetree/bindings/media/allwinner,sun4i-a10-csi.yaml
 S:	Maintained
 
diff --git a/drivers/media/platform/sunxi/Kconfig b/drivers/media/platform/sunxi/Kconfig
index 1b6e89cb78b2..71808e93ac2e 100644
--- a/drivers/media/platform/sunxi/Kconfig
+++ b/drivers/media/platform/sunxi/Kconfig
@@ -1 +1,2 @@
+source "drivers/media/platform/sunxi/sun4i-csi/Kconfig"
 source "drivers/media/platform/sunxi/sun6i-csi/Kconfig"
diff --git a/drivers/media/platform/sunxi/Makefile b/drivers/media/platform/sunxi/Makefile
index 8d06f98500ee..a05127529006 100644
--- a/drivers/media/platform/sunxi/Makefile
+++ b/drivers/media/platform/sunxi/Makefile
@@ -1 +1,2 @@
+obj-y		+= sun4i-csi/
 obj-y		+= sun6i-csi/
diff --git a/drivers/media/platform/sunxi/sun4i-csi/Kconfig b/drivers/media/platform/sunxi/sun4i-csi/Kconfig
new file mode 100644
index 000000000000..e86e29b6a603
--- /dev/null
+++ b/drivers/media/platform/sunxi/sun4i-csi/Kconfig
@@ -0,0 +1,11 @@
+config VIDEO_SUN4I_CSI
+	tristate "Allwinner A10 CMOS Sensor Interface Support"
+	depends on VIDEO_V4L2 && COMMON_CLK && VIDEO_V4L2_SUBDEV_API && HAS_DMA
+	depends on ARCH_SUNXI || COMPILE_TEST
+	select VIDEOBUF2_DMA_CONTIG
+	select V4L2_FWNODE
+	help
+	  This is a V4L2 driver for the Allwinner A10 CSI
+
+	  To compile this driver as a module, choose M here: the module
+	  will be called sun4i_csi.
diff --git a/drivers/media/platform/sunxi/sun4i-csi/Makefile b/drivers/media/platform/sunxi/sun4i-csi/Makefile
new file mode 100644
index 000000000000..7c790a57f5ee
--- /dev/null
+++ b/drivers/media/platform/sunxi/sun4i-csi/Makefile
@@ -0,0 +1,5 @@
+sun4i-csi-y += sun4i_csi.o
+sun4i-csi-y += sun4i_dma.o
+sun4i-csi-y += sun4i_v4l2.o
+
+obj-$(CONFIG_VIDEO_SUN4I_CSI)	+= sun4i-csi.o
diff --git a/drivers/media/platform/sunxi/sun4i-csi/sun4i_csi.c b/drivers/media/platform/sunxi/sun4i-csi/sun4i_csi.c
new file mode 100644
index 000000000000..1929b3a85039
--- /dev/null
+++ b/drivers/media/platform/sunxi/sun4i-csi/sun4i_csi.c
@@ -0,0 +1,312 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2016 NextThing Co
+ * Copyright (C) 2016-2019 Bootlin
+ *
+ * Author: Maxime Ripard <maxime.ripard@bootlin.com>
+ */
+
+#include <linux/clk.h>
+#include <linux/interrupt.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/of.h>
+#include <linux/of_graph.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/reset.h>
+#include <linux/videodev2.h>
+
+#include <media/v4l2-dev.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-fwnode.h>
+#include <media/v4l2-ioctl.h>
+#include <media/v4l2-mediabus.h>
+
+#include <media/videobuf2-core.h>
+#include <media/videobuf2-dma-contig.h>
+
+#include "sun4i_csi.h"
+
+static const struct media_entity_operations sun4i_csi_video_entity_ops = {
+	.link_validate = v4l2_subdev_link_validate,
+};
+
+static int sun4i_csi_notify_bound(struct v4l2_async_notifier *notifier,
+				  struct v4l2_subdev *subdev,
+				  struct v4l2_async_subdev *asd)
+{
+	struct sun4i_csi *csi = container_of(notifier, struct sun4i_csi,
+					     notifier);
+
+	csi->src_subdev = subdev;
+	csi->src_pad = media_entity_get_fwnode_pad(&subdev->entity,
+						   subdev->fwnode,
+						   MEDIA_PAD_FL_SOURCE);
+	if (csi->src_pad < 0) {
+		dev_err(csi->dev, "Couldn't find output pad for subdev %s\n",
+			subdev->name);
+		return csi->src_pad;
+	}
+
+	dev_dbg(csi->dev, "Bound %s pad: %d\n", subdev->name, csi->src_pad);
+	return 0;
+}
+
+static int sun4i_csi_notify_complete(struct v4l2_async_notifier *notifier)
+{
+	struct sun4i_csi *csi = container_of(notifier, struct sun4i_csi,
+					     notifier);
+	struct v4l2_subdev *subdev = &csi->subdev;
+	struct video_device *vdev = &csi->vdev;
+	int ret;
+
+	ret = v4l2_device_register_subdev(&csi->v4l, subdev);
+	if (ret < 0)
+		return ret;
+
+	ret = sun4i_csi_v4l2_register(csi);
+	if (ret < 0)
+		return ret;
+
+	ret = media_device_register(&csi->mdev);
+	if (ret)
+		return ret;
+
+	/* Create link from subdev to main device */
+	ret = media_create_pad_link(&subdev->entity, CSI_SUBDEV_SOURCE,
+				    &vdev->entity, 0,
+				    MEDIA_LNK_FL_ENABLED | MEDIA_LNK_FL_IMMUTABLE);
+	if (ret)
+		goto err_clean_media;
+
+	ret = media_create_pad_link(&csi->src_subdev->entity, csi->src_pad,
+				    &subdev->entity, CSI_SUBDEV_SINK,
+				    MEDIA_LNK_FL_ENABLED | MEDIA_LNK_FL_IMMUTABLE);
+	if (ret)
+		goto err_clean_media;
+
+	ret = v4l2_device_register_subdev_nodes(&csi->v4l);
+	if (ret < 0)
+		goto err_clean_media;
+
+	return 0;
+
+err_clean_media:
+	media_device_unregister(&csi->mdev);
+
+	return ret;
+}
+
+static const struct v4l2_async_notifier_operations sun4i_csi_notify_ops = {
+	.bound		= sun4i_csi_notify_bound,
+	.complete	= sun4i_csi_notify_complete,
+};
+
+static int sun4i_csi_notifier_init(struct sun4i_csi *csi)
+{
+	struct v4l2_fwnode_endpoint vep = {
+		.bus_type = V4L2_MBUS_PARALLEL,
+	};
+	struct fwnode_handle *ep;
+	int ret;
+
+	v4l2_async_notifier_init(&csi->notifier);
+
+	ep = fwnode_graph_get_endpoint_by_id(dev_fwnode(csi->dev), 0, 0,
+					     FWNODE_GRAPH_ENDPOINT_NEXT);
+	if (!ep)
+		return -EINVAL;
+
+	ret = v4l2_fwnode_endpoint_parse(ep, &vep);
+	if (ret)
+		goto out;
+
+	csi->bus = vep.bus.parallel;
+
+	ret = v4l2_async_notifier_add_fwnode_remote_subdev(&csi->notifier,
+							   ep, &csi->asd);
+	if (ret)
+		goto out;
+
+	csi->notifier.ops = &sun4i_csi_notify_ops;
+
+out:
+	fwnode_handle_put(ep);
+	return ret;
+}
+
+static int sun4i_csi_probe(struct platform_device *pdev)
+{
+	struct v4l2_subdev *subdev;
+	struct video_device *vdev;
+	struct sun4i_csi *csi;
+	struct resource *res;
+	int ret;
+	int irq;
+
+	csi = devm_kzalloc(&pdev->dev, sizeof(*csi), GFP_KERNEL);
+	if (!csi)
+		return -ENOMEM;
+	platform_set_drvdata(pdev, csi);
+	csi->dev = &pdev->dev;
+	subdev = &csi->subdev;
+	vdev = &csi->vdev;
+
+	csi->mdev.dev = csi->dev;
+	strscpy(csi->mdev.model, "Allwinner Video Capture Device",
+		sizeof(csi->mdev.model));
+	csi->mdev.hw_revision = 0;
+	media_device_init(&csi->mdev);
+	csi->v4l.mdev = &csi->mdev;
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	csi->regs = devm_ioremap_resource(&pdev->dev, res);
+	if (IS_ERR(csi->regs))
+		return PTR_ERR(csi->regs);
+
+	irq = platform_get_irq(pdev, 0);
+	if (irq < 0)
+		return irq;
+
+	csi->bus_clk = devm_clk_get(&pdev->dev, "bus");
+	if (IS_ERR(csi->bus_clk)) {
+		dev_err(&pdev->dev, "Couldn't get our bus clock\n");
+		return PTR_ERR(csi->bus_clk);
+	}
+
+	csi->isp_clk = devm_clk_get(&pdev->dev, "isp");
+	if (IS_ERR(csi->isp_clk)) {
+		dev_err(&pdev->dev, "Couldn't get our ISP clock\n");
+		return PTR_ERR(csi->isp_clk);
+	}
+
+	csi->ram_clk = devm_clk_get(&pdev->dev, "ram");
+	if (IS_ERR(csi->ram_clk)) {
+		dev_err(&pdev->dev, "Couldn't get our ram clock\n");
+		return PTR_ERR(csi->ram_clk);
+	}
+
+	csi->rst = devm_reset_control_get(&pdev->dev, NULL);
+	if (IS_ERR(csi->rst)) {
+		dev_err(&pdev->dev, "Couldn't get our reset line\n");
+		return PTR_ERR(csi->rst);
+	}
+
+	/* Initialize subdev */
+	v4l2_subdev_init(subdev, &sun4i_csi_subdev_ops);
+	subdev->flags = V4L2_SUBDEV_FL_HAS_DEVNODE | V4L2_SUBDEV_FL_HAS_EVENTS;
+	subdev->entity.function = MEDIA_ENT_F_VID_IF_BRIDGE;
+	subdev->owner = THIS_MODULE;
+	snprintf(subdev->name, sizeof(subdev->name), "sun4i-csi-0");
+	v4l2_set_subdevdata(subdev, csi);
+
+	csi->subdev_pads[CSI_SUBDEV_SINK].flags =
+		MEDIA_PAD_FL_SINK | MEDIA_PAD_FL_MUST_CONNECT;
+	csi->subdev_pads[CSI_SUBDEV_SOURCE].flags = MEDIA_PAD_FL_SOURCE;
+	ret = media_entity_pads_init(&subdev->entity, CSI_SUBDEV_PADS,
+				     csi->subdev_pads);
+	if (ret < 0)
+		return ret;
+
+	csi->vdev_pad.flags = MEDIA_PAD_FL_SINK | MEDIA_PAD_FL_MUST_CONNECT;
+	vdev->entity.ops = &sun4i_csi_video_entity_ops;
+	ret = media_entity_pads_init(&vdev->entity, 1, &csi->vdev_pad);
+	if (ret < 0)
+		return ret;
+
+	ret = sun4i_csi_dma_register(csi, irq);
+	if (ret)
+		goto err_clean_pad;
+
+	ret = sun4i_csi_notifier_init(csi);
+	if (ret)
+		goto err_unregister_media;
+
+	ret = v4l2_async_notifier_register(&csi->v4l, &csi->notifier);
+	if (ret) {
+		dev_err(csi->dev, "Couldn't register our notifier.\n");
+		goto err_unregister_media;
+	}
+
+	pm_runtime_enable(&pdev->dev);
+
+	return 0;
+
+err_unregister_media:
+	media_device_unregister(&csi->mdev);
+	sun4i_csi_dma_unregister(csi);
+
+err_clean_pad:
+	media_device_cleanup(&csi->mdev);
+
+	return ret;
+}
+
+static int sun4i_csi_remove(struct platform_device *pdev)
+{
+	struct sun4i_csi *csi = platform_get_drvdata(pdev);
+
+	v4l2_async_notifier_unregister(&csi->notifier);
+	v4l2_async_notifier_cleanup(&csi->notifier);
+	media_device_unregister(&csi->mdev);
+	sun4i_csi_dma_unregister(csi);
+	media_device_cleanup(&csi->mdev);
+
+	return 0;
+}
+
+static const struct of_device_id sun4i_csi_of_match[] = {
+	{ .compatible = "allwinner,sun7i-a20-csi0" },
+	{ /* Sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, sun4i_csi_of_match);
+
+static int __maybe_unused sun4i_csi_runtime_resume(struct device *dev)
+{
+	struct sun4i_csi *csi = dev_get_drvdata(dev);
+
+	reset_control_deassert(csi->rst);
+	clk_prepare_enable(csi->bus_clk);
+	clk_prepare_enable(csi->ram_clk);
+	clk_set_rate(csi->isp_clk, 80000000);
+	clk_prepare_enable(csi->isp_clk);
+
+	writel(1, csi->regs + CSI_EN_REG);
+
+	return 0;
+}
+
+static int __maybe_unused sun4i_csi_runtime_suspend(struct device *dev)
+{
+	struct sun4i_csi *csi = dev_get_drvdata(dev);
+
+	clk_disable_unprepare(csi->isp_clk);
+	clk_disable_unprepare(csi->ram_clk);
+	clk_disable_unprepare(csi->bus_clk);
+
+	reset_control_assert(csi->rst);
+
+	return 0;
+}
+
+static const struct dev_pm_ops sun4i_csi_pm_ops = {
+	SET_RUNTIME_PM_OPS(sun4i_csi_runtime_suspend,
+			   sun4i_csi_runtime_resume,
+			   NULL)
+};
+
+static struct platform_driver sun4i_csi_driver = {
+	.probe	= sun4i_csi_probe,
+	.remove	= sun4i_csi_remove,
+	.driver	= {
+		.name		= "sun4i-csi",
+		.of_match_table	= sun4i_csi_of_match,
+		.pm		= &sun4i_csi_pm_ops,
+	},
+};
+module_platform_driver(sun4i_csi_driver);
+
+MODULE_DESCRIPTION("Allwinner A10 Camera Sensor Interface driver");
+MODULE_AUTHOR("Maxime Ripard <mripard@kernel.org>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/platform/sunxi/sun4i-csi/sun4i_csi.h b/drivers/media/platform/sunxi/sun4i-csi/sun4i_csi.h
new file mode 100644
index 000000000000..001c8bde006c
--- /dev/null
+++ b/drivers/media/platform/sunxi/sun4i-csi/sun4i_csi.h
@@ -0,0 +1,160 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * Copyright (C) 2016 NextThing Co
+ * Copyright (C) 2016-2019 Bootlin
+ *
+ * Author: Maxime Ripard <maxime.ripard@bootlin.com>
+ */
+
+#ifndef _SUN4I_CSI_H_
+#define _SUN4I_CSI_H_
+
+#include <media/media-device.h>
+#include <media/v4l2-async.h>
+#include <media/v4l2-dev.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-fwnode.h>
+#include <media/videobuf2-core.h>
+
+#define CSI_EN_REG			0x00
+
+#define CSI_CFG_REG			0x04
+#define CSI_CFG_INPUT_FMT(fmt)			((fmt) << 20)
+#define CSI_CFG_OUTPUT_FMT(fmt)			((fmt) << 16)
+#define CSI_CFG_YUV_DATA_SEQ(seq)		((seq) << 8)
+#define CSI_CFG_VSYNC_POL(pol)			((pol) << 2)
+#define CSI_CFG_HSYNC_POL(pol)			((pol) << 1)
+#define CSI_CFG_PCLK_POL(pol)			((pol) << 0)
+
+#define CSI_CPT_CTRL_REG		0x08
+#define CSI_CPT_CTRL_VIDEO_START		BIT(1)
+#define CSI_CPT_CTRL_IMAGE_START		BIT(0)
+
+#define CSI_BUF_ADDR_REG(fifo, buf)	(0x10 + (0x8 * (fifo)) + (0x4 * (buf)))
+
+#define CSI_BUF_CTRL_REG		0x28
+#define CSI_BUF_CTRL_DBN			BIT(2)
+#define CSI_BUF_CTRL_DBS			BIT(1)
+#define CSI_BUF_CTRL_DBE			BIT(0)
+
+#define CSI_INT_EN_REG			0x30
+#define CSI_INT_FRM_DONE			BIT(1)
+#define CSI_INT_CPT_DONE			BIT(0)
+
+#define CSI_INT_STA_REG			0x34
+
+#define CSI_WIN_CTRL_W_REG		0x40
+#define CSI_WIN_CTRL_W_ACTIVE(w)		((w) << 16)
+
+#define CSI_WIN_CTRL_H_REG		0x44
+#define CSI_WIN_CTRL_H_ACTIVE(h)		((h) << 16)
+
+#define CSI_BUF_LEN_REG			0x48
+
+#define CSI_MAX_BUFFER		2
+#define CSI_MAX_HEIGHT		8192U
+#define CSI_MAX_WIDTH		8192U
+
+enum csi_input {
+	CSI_INPUT_RAW	= 0,
+	CSI_INPUT_BT656	= 2,
+	CSI_INPUT_YUV	= 3,
+};
+
+enum csi_output_raw {
+	CSI_OUTPUT_RAW_PASSTHROUGH = 0,
+};
+
+enum csi_output_yuv {
+	CSI_OUTPUT_YUV_422_PLANAR	= 0,
+	CSI_OUTPUT_YUV_420_PLANAR	= 1,
+	CSI_OUTPUT_YUV_422_UV		= 4,
+	CSI_OUTPUT_YUV_420_UV		= 5,
+	CSI_OUTPUT_YUV_422_MACRO	= 8,
+	CSI_OUTPUT_YUV_420_MACRO	= 9,
+};
+
+enum csi_yuv_data_seq {
+	CSI_YUV_DATA_SEQ_YUYV	= 0,
+	CSI_YUV_DATA_SEQ_YVYU	= 1,
+	CSI_YUV_DATA_SEQ_UYVY	= 2,
+	CSI_YUV_DATA_SEQ_VYUY	= 3,
+};
+
+enum csi_subdev_pads {
+	CSI_SUBDEV_SINK,
+	CSI_SUBDEV_SOURCE,
+
+	CSI_SUBDEV_PADS,
+};
+
+extern const struct v4l2_subdev_ops sun4i_csi_subdev_ops;
+
+struct sun4i_csi_format {
+	u32			mbus;
+	u32			fourcc;
+	enum csi_input		input;
+	u32			output;
+	unsigned int		num_planes;
+	u8			bpp[3];
+	unsigned int		hsub;
+	unsigned int		vsub;
+};
+
+const struct sun4i_csi_format *sun4i_csi_find_format(const u32 *fourcc,
+						     const u32 *mbus);
+
+struct sun4i_csi {
+	/* Device resources */
+	struct device			*dev;
+
+	void __iomem			*regs;
+	struct clk			*bus_clk;
+	struct clk			*isp_clk;
+	struct clk			*ram_clk;
+	struct reset_control		*rst;
+
+	struct vb2_v4l2_buffer		*current_buf[CSI_MAX_BUFFER];
+
+	struct {
+		size_t			size;
+		void			*vaddr;
+		dma_addr_t		paddr;
+	} scratch;
+
+	struct v4l2_fwnode_bus_parallel	bus;
+
+	/* Main Device */
+	struct v4l2_device		v4l;
+	struct media_device		mdev;
+	struct video_device		vdev;
+	struct media_pad		vdev_pad;
+	struct v4l2_pix_format_mplane	fmt;
+
+	/* Local subdev */
+	struct v4l2_subdev		subdev;
+	struct media_pad		subdev_pads[CSI_SUBDEV_PADS];
+	struct v4l2_mbus_framefmt	subdev_fmt;
+
+	/* V4L2 Async variables */
+	struct v4l2_async_subdev	asd;
+	struct v4l2_async_notifier	notifier;
+	struct v4l2_subdev		*src_subdev;
+	int				src_pad;
+
+	/* V4L2 variables */
+	struct mutex			lock;
+
+	/* Videobuf2 */
+	struct vb2_queue		queue;
+	struct list_head		buf_list;
+	spinlock_t			qlock;
+	unsigned int			sequence;
+};
+
+int sun4i_csi_dma_register(struct sun4i_csi *csi, int irq);
+void sun4i_csi_dma_unregister(struct sun4i_csi *csi);
+
+int sun4i_csi_v4l2_register(struct sun4i_csi *csi);
+
+#endif /* _SUN4I_CSI_H_ */
diff --git a/drivers/media/platform/sunxi/sun4i-csi/sun4i_dma.c b/drivers/media/platform/sunxi/sun4i-csi/sun4i_dma.c
new file mode 100644
index 000000000000..fe1803375dd4
--- /dev/null
+++ b/drivers/media/platform/sunxi/sun4i-csi/sun4i_dma.c
@@ -0,0 +1,453 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2016 NextThing Co
+ * Copyright (C) 2016-2019 Bootlin
+ *
+ * Author: Maxime Ripard <maxime.ripard@bootlin.com>
+ */
+
+#include <linux/device.h>
+#include <linux/interrupt.h>
+#include <linux/list.h>
+#include <linux/mutex.h>
+#include <linux/spinlock.h>
+#include <media/videobuf2-dma-contig.h>
+#include <media/videobuf2-v4l2.h>
+
+#include "sun4i_csi.h"
+
+struct sun4i_csi_buffer {
+	struct vb2_v4l2_buffer	vb;
+	struct list_head	list;
+};
+
+static inline struct sun4i_csi_buffer *
+vb2_v4l2_to_csi_buffer(const struct vb2_v4l2_buffer *p)
+{
+	return container_of(p, struct sun4i_csi_buffer, vb);
+}
+
+static inline struct sun4i_csi_buffer *
+vb2_to_csi_buffer(const struct vb2_buffer *p)
+{
+	return vb2_v4l2_to_csi_buffer(to_vb2_v4l2_buffer(p));
+}
+
+static void sun4i_csi_capture_start(struct sun4i_csi *csi)
+{
+	writel(CSI_CPT_CTRL_VIDEO_START, csi->regs + CSI_CPT_CTRL_REG);
+}
+
+static void sun4i_csi_capture_stop(struct sun4i_csi *csi)
+{
+	writel(0, csi->regs + CSI_CPT_CTRL_REG);
+}
+
+static int sun4i_csi_queue_setup(struct vb2_queue *vq,
+				 unsigned int *nbuffers,
+				 unsigned int *nplanes,
+				 unsigned int sizes[],
+				 struct device *alloc_devs[])
+{
+	struct sun4i_csi *csi = vb2_get_drv_priv(vq);
+	unsigned int num_planes = csi->fmt.num_planes;
+	unsigned int i;
+
+	if (*nplanes) {
+		if (*nplanes != num_planes)
+			return -EINVAL;
+
+		for (i = 0; i < num_planes; i++)
+			if (sizes[i] < csi->fmt.plane_fmt[i].sizeimage)
+				return -EINVAL;
+		return 0;
+	}
+
+	*nplanes = num_planes;
+	for (i = 0; i < num_planes; i++)
+		sizes[i] = csi->fmt.plane_fmt[i].sizeimage;
+
+	return 0;
+};
+
+static int sun4i_csi_buffer_prepare(struct vb2_buffer *vb)
+{
+	struct sun4i_csi *csi = vb2_get_drv_priv(vb->vb2_queue);
+	unsigned int i;
+
+	for (i = 0; i < csi->fmt.num_planes; i++) {
+		unsigned long size = csi->fmt.plane_fmt[i].sizeimage;
+
+		if (vb2_plane_size(vb, i) < size) {
+			dev_err(csi->dev, "buffer too small (%lu < %lu)\n",
+				vb2_plane_size(vb, i), size);
+			return -EINVAL;
+		}
+
+		vb2_set_plane_payload(vb, i, size);
+	}
+
+	return 0;
+}
+
+static int sun4i_csi_setup_scratch_buffer(struct sun4i_csi *csi, unsigned int slot)
+{
+	dma_addr_t addr = csi->scratch.paddr;
+	unsigned int plane;
+
+	dev_dbg(csi->dev,
+		"No more available buffer, using the scratch buffer\n");
+
+	for (plane = 0; plane < csi->fmt.num_planes; plane++) {
+		writel(addr, csi->regs + CSI_BUF_ADDR_REG(plane, slot));
+		addr += csi->fmt.plane_fmt[plane].sizeimage;
+	}
+
+	csi->current_buf[slot] = NULL;
+	return 0;
+}
+
+static int sun4i_csi_buffer_fill_slot(struct sun4i_csi *csi, unsigned int slot)
+{
+	struct sun4i_csi_buffer *c_buf;
+	struct vb2_v4l2_buffer *v_buf;
+	unsigned int plane;
+
+	/*
+	 * We should never end up in a situation where we overwrite an
+	 * already filled slot.
+	 */
+	if (WARN_ON(csi->current_buf[slot]))
+		return -EINVAL;
+
+	if (list_empty(&csi->buf_list))
+		return sun4i_csi_setup_scratch_buffer(csi, slot);
+
+	c_buf = list_first_entry(&csi->buf_list, struct sun4i_csi_buffer, list);
+	list_del_init(&c_buf->list);
+
+	v_buf = &c_buf->vb;
+	csi->current_buf[slot] = v_buf;
+
+	for (plane = 0; plane < csi->fmt.num_planes; plane++) {
+		dma_addr_t buf_addr;
+
+		buf_addr = vb2_dma_contig_plane_dma_addr(&v_buf->vb2_buf,
+							 plane);
+		writel(buf_addr, csi->regs + CSI_BUF_ADDR_REG(plane, slot));
+	}
+
+	return 0;
+}
+
+static int sun4i_csi_buffer_fill_all(struct sun4i_csi *csi)
+{
+	unsigned int slot;
+	int ret;
+
+	for (slot = 0; slot < CSI_MAX_BUFFER; slot++) {
+		ret = sun4i_csi_buffer_fill_slot(csi, slot);
+		if (ret)
+			return ret;
+	}
+
+	return 0;
+}
+
+static void sun4i_csi_buffer_mark_done(struct sun4i_csi *csi,
+				       unsigned int slot,
+				       unsigned int sequence)
+{
+	struct vb2_v4l2_buffer *v_buf;
+
+	if (!csi->current_buf[slot]) {
+		dev_dbg(csi->dev, "Scratch buffer was used, ignoring..\n");
+		return;
+	}
+
+	v_buf = csi->current_buf[slot];
+	v_buf->field = csi->fmt.field;
+	v_buf->sequence = sequence;
+	v_buf->vb2_buf.timestamp = ktime_get_ns();
+	vb2_buffer_done(&v_buf->vb2_buf, VB2_BUF_STATE_DONE);
+
+	csi->current_buf[slot] = NULL;
+}
+
+static int sun4i_csi_buffer_flip(struct sun4i_csi *csi, unsigned int sequence)
+{
+	u32 reg = readl(csi->regs + CSI_BUF_CTRL_REG);
+	unsigned int next;
+
+	/* Our next buffer is not the current buffer */
+	next = !(reg & CSI_BUF_CTRL_DBS);
+
+	/* Report the previous buffer as done */
+	sun4i_csi_buffer_mark_done(csi, next, sequence);
+
+	/* Put a new buffer in there */
+	return sun4i_csi_buffer_fill_slot(csi, next);
+}
+
+static void sun4i_csi_buffer_queue(struct vb2_buffer *vb)
+{
+	struct sun4i_csi *csi = vb2_get_drv_priv(vb->vb2_queue);
+	struct sun4i_csi_buffer *buf = vb2_to_csi_buffer(vb);
+	unsigned long flags;
+
+	spin_lock_irqsave(&csi->qlock, flags);
+	list_add_tail(&buf->list, &csi->buf_list);
+	spin_unlock_irqrestore(&csi->qlock, flags);
+}
+
+static void return_all_buffers(struct sun4i_csi *csi,
+			       enum vb2_buffer_state state)
+{
+	struct sun4i_csi_buffer *buf, *node;
+	unsigned int slot;
+
+	list_for_each_entry_safe(buf, node, &csi->buf_list, list) {
+		vb2_buffer_done(&buf->vb.vb2_buf, state);
+		list_del(&buf->list);
+	}
+
+	for (slot = 0; slot < CSI_MAX_BUFFER; slot++) {
+		struct vb2_v4l2_buffer *v_buf = csi->current_buf[slot];
+
+		if (!v_buf)
+			continue;
+
+		vb2_buffer_done(&v_buf->vb2_buf, state);
+		csi->current_buf[slot] = NULL;
+	}
+}
+
+static int sun4i_csi_start_streaming(struct vb2_queue *vq, unsigned int count)
+{
+	struct sun4i_csi *csi = vb2_get_drv_priv(vq);
+	struct v4l2_fwnode_bus_parallel *bus = &csi->bus;
+	const struct sun4i_csi_format *csi_fmt;
+	unsigned long hsync_pol, pclk_pol, vsync_pol;
+	unsigned long flags;
+	unsigned int i;
+	int ret;
+
+	csi_fmt = sun4i_csi_find_format(&csi->fmt.pixelformat, NULL);
+	if (!csi_fmt)
+		return -EINVAL;
+
+	dev_dbg(csi->dev, "Starting capture\n");
+
+	csi->sequence = 0;
+
+	/*
+	 * We need a scratch buffer in case where we'll not have any
+	 * more buffer queued so that we don't error out. One of those
+	 * cases is when you end up at the last frame to capture, you
+	 * don't havea any buffer queued any more, and yet it doesn't
+	 * really matter since you'll never reach the next buffer.
+	 *
+	 * Since we support the multi-planar API, we need to have a
+	 * buffer for each plane. Allocating a single one large enough
+	 * to hold all the buffers is simpler, so let's go for that.
+	 */
+	csi->scratch.size = 0;
+	for (i = 0; i < csi->fmt.num_planes; i++)
+		csi->scratch.size += csi->fmt.plane_fmt[i].sizeimage;
+
+	csi->scratch.vaddr = dma_alloc_coherent(csi->dev,
+						csi->scratch.size,
+						&csi->scratch.paddr,
+						GFP_KERNEL);
+	if (!csi->scratch.vaddr) {
+		dev_err(csi->dev, "Failed to allocate scratch buffer\n");
+		ret = -ENOMEM;
+		goto err_clear_dma_queue;
+	}
+
+	ret = media_pipeline_start(&csi->vdev.entity, &csi->vdev.pipe);
+	if (ret < 0)
+		goto err_free_scratch_buffer;
+
+	spin_lock_irqsave(&csi->qlock, flags);
+
+	/* Setup timings */
+	writel(CSI_WIN_CTRL_W_ACTIVE(csi->fmt.width * 2),
+	       csi->regs + CSI_WIN_CTRL_W_REG);
+	writel(CSI_WIN_CTRL_H_ACTIVE(csi->fmt.height),
+	       csi->regs + CSI_WIN_CTRL_H_REG);
+
+	hsync_pol = !!(bus->flags & V4L2_MBUS_HSYNC_ACTIVE_HIGH);
+	pclk_pol = !!(bus->flags & V4L2_MBUS_DATA_ACTIVE_HIGH);
+	vsync_pol = !!(bus->flags & V4L2_MBUS_VSYNC_ACTIVE_HIGH);
+	writel(CSI_CFG_INPUT_FMT(csi_fmt->input) |
+	       CSI_CFG_OUTPUT_FMT(csi_fmt->output) |
+	       CSI_CFG_VSYNC_POL(vsync_pol) |
+	       CSI_CFG_HSYNC_POL(hsync_pol) |
+	       CSI_CFG_PCLK_POL(pclk_pol),
+	       csi->regs + CSI_CFG_REG);
+
+	/* Setup buffer length */
+	writel(csi->fmt.plane_fmt[0].bytesperline,
+	       csi->regs + CSI_BUF_LEN_REG);
+
+	/* Prepare our buffers in hardware */
+	ret = sun4i_csi_buffer_fill_all(csi);
+	if (ret) {
+		spin_unlock_irqrestore(&csi->qlock, flags);
+		goto err_disable_pipeline;
+	}
+
+	/* Enable double buffering */
+	writel(CSI_BUF_CTRL_DBE, csi->regs + CSI_BUF_CTRL_REG);
+
+	/* Clear the pending interrupts */
+	writel(CSI_INT_FRM_DONE, csi->regs + 0x34);
+
+	/* Enable frame done interrupt */
+	writel(CSI_INT_FRM_DONE, csi->regs + CSI_INT_EN_REG);
+
+	sun4i_csi_capture_start(csi);
+
+	spin_unlock_irqrestore(&csi->qlock, flags);
+
+	ret = v4l2_subdev_call(csi->src_subdev, video, s_stream, 1);
+	if (ret < 0 && ret != -ENOIOCTLCMD)
+		goto err_disable_device;
+
+	return 0;
+
+err_disable_device:
+	sun4i_csi_capture_stop(csi);
+
+err_disable_pipeline:
+	media_pipeline_stop(&csi->vdev.entity);
+
+err_free_scratch_buffer:
+	dma_free_coherent(csi->dev, csi->scratch.size, csi->scratch.vaddr,
+			  csi->scratch.paddr);
+
+err_clear_dma_queue:
+	spin_lock_irqsave(&csi->qlock, flags);
+	return_all_buffers(csi, VB2_BUF_STATE_QUEUED);
+	spin_unlock_irqrestore(&csi->qlock, flags);
+
+	return ret;
+}
+
+static void sun4i_csi_stop_streaming(struct vb2_queue *vq)
+{
+	struct sun4i_csi *csi = vb2_get_drv_priv(vq);
+	unsigned long flags;
+
+	dev_dbg(csi->dev, "Stopping capture\n");
+
+	v4l2_subdev_call(csi->src_subdev, video, s_stream, 0);
+	sun4i_csi_capture_stop(csi);
+
+	/* Release all active buffers */
+	spin_lock_irqsave(&csi->qlock, flags);
+	return_all_buffers(csi, VB2_BUF_STATE_ERROR);
+	spin_unlock_irqrestore(&csi->qlock, flags);
+
+	media_pipeline_stop(&csi->vdev.entity);
+
+	dma_free_coherent(csi->dev, csi->scratch.size, csi->scratch.vaddr,
+			  csi->scratch.paddr);
+}
+
+static const struct vb2_ops sun4i_csi_qops = {
+	.queue_setup		= sun4i_csi_queue_setup,
+	.buf_prepare		= sun4i_csi_buffer_prepare,
+	.buf_queue		= sun4i_csi_buffer_queue,
+	.start_streaming	= sun4i_csi_start_streaming,
+	.stop_streaming		= sun4i_csi_stop_streaming,
+	.wait_prepare		= vb2_ops_wait_prepare,
+	.wait_finish		= vb2_ops_wait_finish,
+};
+
+static irqreturn_t sun4i_csi_irq(int irq, void *data)
+{
+	struct sun4i_csi *csi = data;
+	u32 reg;
+
+	reg = readl(csi->regs + CSI_INT_STA_REG);
+
+	/* Acknowledge the interrupts */
+	writel(reg, csi->regs + CSI_INT_STA_REG);
+
+	if (!(reg & CSI_INT_FRM_DONE))
+		return IRQ_HANDLED;
+
+	spin_lock(&csi->qlock);
+	if (sun4i_csi_buffer_flip(csi, csi->sequence++)) {
+		dev_warn(csi->dev, "%s: Flip failed\n", __func__);
+		sun4i_csi_capture_stop(csi);
+	}
+	spin_unlock(&csi->qlock);
+
+	return IRQ_HANDLED;
+}
+
+int sun4i_csi_dma_register(struct sun4i_csi *csi, int irq)
+{
+	struct vb2_queue *q = &csi->queue;
+	int ret;
+	int i;
+
+	spin_lock_init(&csi->qlock);
+	mutex_init(&csi->lock);
+
+	INIT_LIST_HEAD(&csi->buf_list);
+	for (i = 0; i < CSI_MAX_BUFFER; i++)
+		csi->current_buf[i] = NULL;
+
+	q->min_buffers_needed = 3;
+	q->type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
+	q->io_modes = VB2_MMAP;
+	q->lock = &csi->lock;
+	q->drv_priv = csi;
+	q->buf_struct_size = sizeof(struct sun4i_csi_buffer);
+	q->ops = &sun4i_csi_qops;
+	q->mem_ops = &vb2_dma_contig_memops;
+	q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
+	q->dev = csi->dev;
+
+	ret = vb2_queue_init(q);
+	if (ret < 0) {
+		dev_err(csi->dev, "failed to initialize VB2 queue\n");
+		goto err_free_mutex;
+	}
+
+	ret = v4l2_device_register(csi->dev, &csi->v4l);
+	if (ret) {
+		dev_err(csi->dev, "Couldn't register the v4l2 device\n");
+		goto err_free_queue;
+	}
+
+	ret = devm_request_irq(csi->dev, irq, sun4i_csi_irq, 0,
+			       dev_name(csi->dev), csi);
+	if (ret) {
+		dev_err(csi->dev, "Couldn't register our interrupt\n");
+		goto err_unregister_device;
+	}
+
+	return 0;
+
+err_unregister_device:
+	v4l2_device_unregister(&csi->v4l);
+
+err_free_queue:
+	vb2_queue_release(q);
+
+err_free_mutex:
+	mutex_destroy(&csi->lock);
+	return ret;
+}
+
+void sun4i_csi_dma_unregister(struct sun4i_csi *csi)
+{
+	v4l2_device_unregister(&csi->v4l);
+	vb2_queue_release(&csi->queue);
+	mutex_destroy(&csi->lock);
+}
diff --git a/drivers/media/platform/sunxi/sun4i-csi/sun4i_v4l2.c b/drivers/media/platform/sunxi/sun4i-csi/sun4i_v4l2.c
new file mode 100644
index 000000000000..d52b6fe68a09
--- /dev/null
+++ b/drivers/media/platform/sunxi/sun4i-csi/sun4i_v4l2.c
@@ -0,0 +1,385 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2016 NextThing Co
+ * Copyright (C) 2016-2019 Bootlin
+ *
+ * Author: Maxime Ripard <maxime.ripard@bootlin.com>
+ */
+
+#include <linux/device.h>
+#include <linux/pm_runtime.h>
+
+#include <media/v4l2-ioctl.h>
+#include <media/v4l2-mc.h>
+#include <media/videobuf2-v4l2.h>
+
+#include "sun4i_csi.h"
+
+#define CSI_DEFAULT_WIDTH	640
+#define CSI_DEFAULT_HEIGHT	480
+
+const struct sun4i_csi_format sun4i_csi_formats[] = {
+	/* YUV422 inputs */
+	{
+		.mbus		= MEDIA_BUS_FMT_YUYV8_2X8,
+		.fourcc		= V4L2_PIX_FMT_YUV420M,
+		.input		= CSI_INPUT_YUV,
+		.output		= CSI_OUTPUT_YUV_420_PLANAR,
+		.num_planes	= 3,
+		.bpp		= { 8, 8, 8 },
+		.hsub		= 2,
+		.vsub		= 2,
+	},
+};
+
+const struct sun4i_csi_format *sun4i_csi_find_format(const u32 *fourcc,
+						     const u32 *mbus)
+{
+	unsigned int i;
+
+	for (i = 0; i < ARRAY_SIZE(sun4i_csi_formats); i++) {
+		if (fourcc && *fourcc != sun4i_csi_formats[i].fourcc)
+			continue;
+
+		if (mbus && *mbus != sun4i_csi_formats[i].mbus)
+			continue;
+
+		return &sun4i_csi_formats[i];
+	}
+
+	return NULL;
+}
+
+static int sun4i_csi_querycap(struct file *file, void *priv,
+			      struct v4l2_capability *cap)
+{
+	struct sun4i_csi *csi = video_drvdata(file);
+
+	strscpy(cap->driver, KBUILD_MODNAME, sizeof(cap->driver));
+	strscpy(cap->card, "sun4i-csi", sizeof(cap->card));
+	snprintf(cap->bus_info, sizeof(cap->bus_info), "platform:%s",
+		 dev_name(csi->dev));
+
+	return 0;
+}
+
+static int sun4i_csi_enum_input(struct file *file, void *priv,
+				struct v4l2_input *inp)
+{
+	if (inp->index != 0)
+		return -EINVAL;
+
+	inp->type = V4L2_INPUT_TYPE_CAMERA;
+	strscpy(inp->name, "Camera", sizeof(inp->name));
+
+	return 0;
+}
+
+static int sun4i_csi_g_input(struct file *file, void *fh,
+			     unsigned int *i)
+{
+	*i = 0;
+
+	return 0;
+}
+
+static int sun4i_csi_s_input(struct file *file, void *fh,
+			     unsigned int i)
+{
+	if (i != 0)
+		return -EINVAL;
+
+	return 0;
+}
+
+static void _sun4i_csi_try_fmt(struct sun4i_csi *csi,
+			       struct v4l2_pix_format_mplane *pix)
+{
+	const struct sun4i_csi_format *_fmt;
+	unsigned int height, width;
+	unsigned int i;
+
+	_fmt = sun4i_csi_find_format(&pix->pixelformat, NULL);
+	if (!_fmt)
+		_fmt = &sun4i_csi_formats[0];
+
+	pix->field = V4L2_FIELD_NONE;
+	pix->colorspace = V4L2_COLORSPACE_SRGB;
+	pix->xfer_func = V4L2_MAP_XFER_FUNC_DEFAULT(pix->colorspace);
+	pix->ycbcr_enc = V4L2_MAP_YCBCR_ENC_DEFAULT(pix->colorspace);
+	pix->quantization = V4L2_MAP_QUANTIZATION_DEFAULT(true, pix->colorspace,
+							  pix->ycbcr_enc);
+
+	pix->num_planes = _fmt->num_planes;
+	pix->pixelformat = _fmt->fourcc;
+
+	memset(pix->reserved, 0, sizeof(pix->reserved));
+
+	/* Align the width and height on the subsampling */
+	width = ALIGN(pix->width, _fmt->hsub);
+	height = ALIGN(pix->height, _fmt->vsub);
+
+	/* Clamp the width and height to our capabilities */
+	pix->width = clamp(width, _fmt->hsub, CSI_MAX_WIDTH);
+	pix->height = clamp(height, _fmt->vsub, CSI_MAX_HEIGHT);
+
+	for (i = 0; i < _fmt->num_planes; i++) {
+		unsigned int hsub = i > 0 ? _fmt->hsub : 1;
+		unsigned int vsub = i > 0 ? _fmt->vsub : 1;
+		unsigned int bpl;
+
+		bpl = pix->width / hsub * _fmt->bpp[i] / 8;
+		pix->plane_fmt[i].bytesperline = bpl;
+		pix->plane_fmt[i].sizeimage = bpl * pix->height / vsub;
+		memset(pix->plane_fmt[i].reserved, 0,
+		       sizeof(pix->plane_fmt[i].reserved));
+	}
+}
+
+static int sun4i_csi_try_fmt_vid_cap(struct file *file, void *priv,
+				     struct v4l2_format *f)
+{
+	struct sun4i_csi *csi = video_drvdata(file);
+
+	_sun4i_csi_try_fmt(csi, &f->fmt.pix_mp);
+
+	return 0;
+}
+
+static int sun4i_csi_s_fmt_vid_cap(struct file *file, void *priv,
+				   struct v4l2_format *f)
+{
+	struct sun4i_csi *csi = video_drvdata(file);
+
+	_sun4i_csi_try_fmt(csi, &f->fmt.pix_mp);
+	csi->fmt = f->fmt.pix_mp;
+
+	return 0;
+}
+
+static int sun4i_csi_g_fmt_vid_cap(struct file *file, void *priv,
+				   struct v4l2_format *f)
+{
+	struct sun4i_csi *csi = video_drvdata(file);
+
+	f->fmt.pix_mp = csi->fmt;
+
+	return 0;
+}
+
+static int sun4i_csi_enum_fmt_vid_cap(struct file *file, void *priv,
+				      struct v4l2_fmtdesc *f)
+{
+	if (f->index >= ARRAY_SIZE(sun4i_csi_formats))
+		return -EINVAL;
+
+	f->pixelformat = sun4i_csi_formats[f->index].fourcc;
+
+	return 0;
+}
+
+static const struct v4l2_ioctl_ops sun4i_csi_ioctl_ops = {
+	.vidioc_querycap		= sun4i_csi_querycap,
+
+	.vidioc_enum_fmt_vid_cap	= sun4i_csi_enum_fmt_vid_cap,
+	.vidioc_g_fmt_vid_cap_mplane	= sun4i_csi_g_fmt_vid_cap,
+	.vidioc_s_fmt_vid_cap_mplane	= sun4i_csi_s_fmt_vid_cap,
+	.vidioc_try_fmt_vid_cap_mplane	= sun4i_csi_try_fmt_vid_cap,
+
+	.vidioc_enum_input		= sun4i_csi_enum_input,
+	.vidioc_g_input			= sun4i_csi_g_input,
+	.vidioc_s_input			= sun4i_csi_s_input,
+
+	.vidioc_reqbufs			= vb2_ioctl_reqbufs,
+	.vidioc_create_bufs		= vb2_ioctl_create_bufs,
+	.vidioc_querybuf		= vb2_ioctl_querybuf,
+	.vidioc_qbuf			= vb2_ioctl_qbuf,
+	.vidioc_dqbuf			= vb2_ioctl_dqbuf,
+	.vidioc_expbuf			= vb2_ioctl_expbuf,
+	.vidioc_prepare_buf		= vb2_ioctl_prepare_buf,
+	.vidioc_streamon		= vb2_ioctl_streamon,
+	.vidioc_streamoff		= vb2_ioctl_streamoff,
+};
+
+static int sun4i_csi_open(struct file *file)
+{
+	struct sun4i_csi *csi = video_drvdata(file);
+	int ret;
+
+	ret = mutex_lock_interruptible(&csi->lock);
+	if (ret)
+		return ret;
+
+	ret = pm_runtime_get_sync(csi->dev);
+	if (ret < 0)
+		goto err_pm_put;
+
+	ret = v4l2_pipeline_pm_use(&csi->vdev.entity, 1);
+	if (ret)
+		goto err_pm_put;
+
+	ret = v4l2_fh_open(file);
+	if (ret)
+		goto err_pipeline_pm_put;
+
+	mutex_unlock(&csi->lock);
+
+	return 0;
+
+err_pipeline_pm_put:
+	v4l2_pipeline_pm_use(&csi->vdev.entity, 0);
+
+err_pm_put:
+	pm_runtime_put(csi->dev);
+	mutex_unlock(&csi->lock);
+
+	return ret;
+}
+
+static int sun4i_csi_release(struct file *file)
+{
+	struct sun4i_csi *csi = video_drvdata(file);
+
+	mutex_lock(&csi->lock);
+
+	v4l2_fh_release(file);
+	v4l2_pipeline_pm_use(&csi->vdev.entity, 0);
+	pm_runtime_put(csi->dev);
+
+	mutex_unlock(&csi->lock);
+
+	return 0;
+}
+
+static const struct v4l2_file_operations sun4i_csi_fops = {
+	.owner		= THIS_MODULE,
+	.open		= sun4i_csi_open,
+	.release	= sun4i_csi_release,
+	.unlocked_ioctl	= video_ioctl2,
+	.read		= vb2_fop_read,
+	.write		= vb2_fop_write,
+	.poll		= vb2_fop_poll,
+	.mmap		= vb2_fop_mmap,
+};
+
+static const struct v4l2_mbus_framefmt sun4i_csi_pad_fmt_default = {
+	.width = CSI_DEFAULT_WIDTH,
+	.height = CSI_DEFAULT_HEIGHT,
+	.code = sun4i_csi_formats[0].mbus,
+	.field = V4L2_FIELD_NONE,
+	.colorspace = V4L2_COLORSPACE_RAW,
+	.ycbcr_enc = V4L2_YCBCR_ENC_DEFAULT,
+	.quantization = V4L2_QUANTIZATION_DEFAULT,
+	.xfer_func = V4L2_XFER_FUNC_DEFAULT,
+};
+
+static int sun4i_csi_subdev_init_cfg(struct v4l2_subdev *subdev,
+				     struct v4l2_subdev_pad_config *cfg)
+{
+	struct v4l2_mbus_framefmt *fmt;
+
+	fmt = v4l2_subdev_get_try_format(subdev, cfg, CSI_SUBDEV_SINK);
+	*fmt = sun4i_csi_pad_fmt_default;
+
+	return 0;
+}
+
+static int sun4i_csi_subdev_get_fmt(struct v4l2_subdev *subdev,
+				    struct v4l2_subdev_pad_config *cfg,
+				    struct v4l2_subdev_format *fmt)
+{
+	struct sun4i_csi *csi = container_of(subdev, struct sun4i_csi, subdev);
+	struct v4l2_mbus_framefmt *subdev_fmt;
+
+	if (fmt->which == V4L2_SUBDEV_FORMAT_TRY)
+		subdev_fmt = v4l2_subdev_get_try_format(subdev, cfg, fmt->pad);
+	else
+		subdev_fmt = &csi->subdev_fmt;
+
+	fmt->format = *subdev_fmt;
+
+	return 0;
+}
+
+static int sun4i_csi_subdev_set_fmt(struct v4l2_subdev *subdev,
+				    struct v4l2_subdev_pad_config *cfg,
+				    struct v4l2_subdev_format *fmt)
+{
+	struct sun4i_csi *csi = container_of(subdev, struct sun4i_csi, subdev);
+	struct v4l2_mbus_framefmt *subdev_fmt;
+
+	if (fmt->which == V4L2_SUBDEV_FORMAT_TRY)
+		subdev_fmt = v4l2_subdev_get_try_format(subdev, cfg, fmt->pad);
+	else
+		subdev_fmt = &csi->subdev_fmt;
+
+	/* We can only set the format on the sink pad */
+	if (fmt->pad == CSI_SUBDEV_SINK) {
+		/* It's the sink, only allow changing the frame size */
+		subdev_fmt->width = fmt->format.width;
+		subdev_fmt->height = fmt->format.height;
+		subdev_fmt->code = fmt->format.code;
+	}
+
+	fmt->format = *subdev_fmt;
+
+	return 0;
+}
+
+static int
+sun4i_csi_subdev_enum_mbus_code(struct v4l2_subdev *subdev,
+				struct v4l2_subdev_pad_config *cfg,
+				struct v4l2_subdev_mbus_code_enum *mbus)
+{
+	if (mbus->index >= ARRAY_SIZE(sun4i_csi_formats))
+		return -EINVAL;
+
+	mbus->code = sun4i_csi_formats[mbus->index].mbus;
+
+	return 0;
+}
+
+static const struct v4l2_subdev_pad_ops sun4i_csi_subdev_pad_ops = {
+	.link_validate	= v4l2_subdev_link_validate_default,
+	.init_cfg	= sun4i_csi_subdev_init_cfg,
+	.get_fmt	= sun4i_csi_subdev_get_fmt,
+	.set_fmt	= sun4i_csi_subdev_set_fmt,
+	.enum_mbus_code	= sun4i_csi_subdev_enum_mbus_code,
+};
+
+const struct v4l2_subdev_ops sun4i_csi_subdev_ops = {
+	.pad = &sun4i_csi_subdev_pad_ops,
+};
+
+int sun4i_csi_v4l2_register(struct sun4i_csi *csi)
+{
+	struct video_device *vdev = &csi->vdev;
+	int ret;
+
+	vdev->device_caps = V4L2_CAP_VIDEO_CAPTURE_MPLANE | V4L2_CAP_STREAMING;
+	vdev->v4l2_dev = &csi->v4l;
+	vdev->queue = &csi->queue;
+	strscpy(vdev->name, KBUILD_MODNAME, sizeof(vdev->name));
+	vdev->release = video_device_release_empty;
+	vdev->lock = &csi->lock;
+
+	/* Set a default format */
+	csi->fmt.pixelformat = sun4i_csi_formats[0].fourcc,
+	csi->fmt.width = CSI_DEFAULT_WIDTH;
+	csi->fmt.height = CSI_DEFAULT_HEIGHT;
+	_sun4i_csi_try_fmt(csi, &csi->fmt);
+	csi->subdev_fmt = sun4i_csi_pad_fmt_default;
+
+	vdev->fops = &sun4i_csi_fops;
+	vdev->ioctl_ops = &sun4i_csi_ioctl_ops;
+	video_set_drvdata(vdev, csi);
+
+	ret = video_register_device(&csi->vdev, VFL_TYPE_GRABBER, -1);
+	if (ret)
+		return ret;
+
+	dev_info(csi->dev, "Device registered as %s\n",
+		 video_device_node_name(vdev));
+
+	return 0;
+}
-- 
git-series 0.9.1

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply related

* [PATCH v8 5/5] DO NOT MERGE: ARM: dts: bananapi: Add Camera support
From: Maxime Ripard @ 2019-08-22  8:21 UTC (permalink / raw)
  To: Hans Verkuil, Sakari Ailus, Mauro Carvalho Chehab
  Cc: Mark Rutland, devicetree, Maxime Ripard, linux-kernel,
	Chen-Yu Tsai, Rob Herring, Laurent Pinchart, Thomas Petazzoni,
	Frank Rowand, linux-arm-kernel, linux-media
In-Reply-To: <cover.85d78dd1a3b44fe4cde1b65a9b1eb3b95daea7cc.1566462064.git-series.maxime.ripard@bootlin.com>

From: Maxime Ripard <maxime.ripard@bootlin.com>

Signed-off-by: Maxime Ripard <maxime.ripard@bootlin.com>
---
 arch/arm/boot/dts/sun7i-a20-bananapi.dts | 87 +++++++++++++++++++++++++-
 1 file changed, 87 insertions(+)

diff --git a/arch/arm/boot/dts/sun7i-a20-bananapi.dts b/arch/arm/boot/dts/sun7i-a20-bananapi.dts
index c5730b30a15d..d3f23ce041b2 100644
--- a/arch/arm/boot/dts/sun7i-a20-bananapi.dts
+++ b/arch/arm/boot/dts/sun7i-a20-bananapi.dts
@@ -54,6 +54,9 @@
 	compatible = "lemaker,bananapi", "allwinner,sun7i-a20";
 
 	aliases {
+		i2c0 = &i2c0;
+		i2c1 = &i2c1;
+		i2c2 = &i2c2;
 		serial0 = &uart0;
 		serial1 = &uart3;
 		serial2 = &uart7;
@@ -63,6 +66,41 @@
 		stdout-path = "serial0:115200n8";
 	};
 
+	reg_cam: cam {
+		compatible = "regulator-fixed";
+		regulator-name = "cam";
+		regulator-min-microvolt = <5000000>;
+		regulator-max-microvolt = <5000000>;
+		vin-supply = <&reg_vcc5v0>;
+		gpio = <&pio 7 16 GPIO_ACTIVE_HIGH>;
+		enable-active-high;
+		regulator-always-on;
+	};
+
+        reg_cam_avdd: cam-avdd {
+                compatible = "regulator-fixed";
+                regulator-name = "cam500b-avdd";
+                regulator-min-microvolt = <2800000>;
+                regulator-max-microvolt = <2800000>;
+                vin-supply = <&reg_cam>;
+        };
+
+        reg_cam_dovdd: cam-dovdd {
+                compatible = "regulator-fixed";
+                regulator-name = "cam500b-dovdd";
+                regulator-min-microvolt = <1800000>;
+                regulator-max-microvolt = <1800000>;
+                vin-supply = <&reg_cam>;
+        };
+
+        reg_cam_dvdd: cam-dvdd {
+                compatible = "regulator-fixed";
+                regulator-name = "cam500b-dvdd";
+                regulator-min-microvolt = <1500000>;
+                regulator-max-microvolt = <1500000>;
+                vin-supply = <&reg_cam>;
+        };
+
 	hdmi-connector {
 		compatible = "hdmi-connector";
 		type = "a";
@@ -116,6 +154,23 @@
 		>;
 };
 
+&csi0 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&csi0_8bits_pins>;
+	status = "okay";
+
+	port {
+		csi_from_ov5640: endpoint {
+                        remote-endpoint = <&ov5640_to_csi>;
+                        bus-width = <8>;
+                        hsync-active = <1>; /* Active high */
+                        vsync-active = <0>; /* Active low */
+                        data-active = <1>;  /* Active high */
+                        pclk-sample = <1>;  /* Rising */
+                };
+	};
+};
+
 &de {
 	status = "okay";
 };
@@ -161,6 +216,38 @@
 	};
 };
 
+&i2c1 {
+	status = "okay";
+
+	camera: camera@21 {
+		compatible = "ovti,ov5640";
+		reg = <0x21>;
+		clocks = <&ccu CLK_CSI0>;
+		clock-names = "xclk";
+		assigned-clocks = <&ccu CLK_CSI0>;
+		assigned-clock-rates = <24000000>;
+		pinctrl-names = "default";
+		pinctrl-0 = <&csi0_clk_pin>;
+
+		reset-gpios = <&pio 7 14 GPIO_ACTIVE_LOW>;
+		powerdown-gpios = <&pio 7 19 GPIO_ACTIVE_HIGH>;
+		AVDD-supply = <&reg_cam_avdd>;
+		DOVDD-supply = <&reg_cam_dovdd>;
+		DVDD-supply = <&reg_cam_dvdd>;
+
+		port {
+			ov5640_to_csi: endpoint {
+				remote-endpoint = <&csi_from_ov5640>;
+				bus-width = <8>;
+				hsync-active = <1>; /* Active high */
+				vsync-active = <0>; /* Active low */
+				data-active = <1>;  /* Active high */
+				pclk-sample = <1>;  /* Rising */
+			};
+		};
+	};
+};
+
 &i2c2 {
 	status = "okay";
 };
-- 
git-series 0.9.1

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply related

* [PATCH v8 4/5] ARM: dts: sun7i: Add CSI0 controller
From: Maxime Ripard @ 2019-08-22  8:21 UTC (permalink / raw)
  To: Hans Verkuil, Sakari Ailus, Mauro Carvalho Chehab
  Cc: Mark Rutland, devicetree, Maxime Ripard, linux-kernel,
	Chen-Yu Tsai, Rob Herring, Laurent Pinchart, Thomas Petazzoni,
	Frank Rowand, linux-arm-kernel, linux-media
In-Reply-To: <cover.85d78dd1a3b44fe4cde1b65a9b1eb3b95daea7cc.1566462064.git-series.maxime.ripard@bootlin.com>

From: Maxime Ripard <maxime.ripard@bootlin.com>

The CSI controller embedded in the A20 can be supported by our new driver.
Let's add it to our DT.

Signed-off-by: Maxime Ripard <maxime.ripard@bootlin.com>
---
 arch/arm/boot/dts/sun7i-a20.dtsi | 25 +++++++++++++++++++++++++
 1 file changed, 25 insertions(+)

diff --git a/arch/arm/boot/dts/sun7i-a20.dtsi b/arch/arm/boot/dts/sun7i-a20.dtsi
index 9ad8e445b240..713c20be8c7a 100644
--- a/arch/arm/boot/dts/sun7i-a20.dtsi
+++ b/arch/arm/boot/dts/sun7i-a20.dtsi
@@ -376,6 +376,17 @@
 			num-cs = <1>;
 		};
 
+		csi0: csi@1c09000 {
+			compatible = "allwinner,sun7i-a20-csi0";
+			reg = <0x01c09000 0x1000>;
+			interrupts = <GIC_SPI 42 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&ccu CLK_AHB_CSI0>, <&ccu CLK_CSI0>,
+				 <&ccu CLK_CSI_SCLK>, <&ccu CLK_DRAM_CSI0>;
+			clock-names = "bus", "mod", "isp", "ram";
+			resets = <&ccu RST_CSI0>;
+			status = "disabled";
+		};
+
 		emac: ethernet@1c0b000 {
 			compatible = "allwinner,sun4i-a10-emac";
 			reg = <0x01c0b000 0x1000>;
@@ -775,6 +786,20 @@
 			};
 
 			/omit-if-no-ref/
+			csi0_8bits_pins: csi-8bits-pins {
+				pins = "PE0", "PE2", "PE3", "PE4", "PE5",
+				       "PE6", "PE7", "PE8", "PE9", "PE10",
+				       "PE11";
+				function = "csi0";
+			};
+
+			/omit-if-no-ref/
+			csi0_clk_pin: csi-clk-pin {
+				pins = "PE1";
+				function = "csi0";
+			};
+
+			/omit-if-no-ref/
 			emac_pa_pins: emac-pa-pins {
 				pins = "PA0", "PA1", "PA2",
 				       "PA3", "PA4", "PA5", "PA6",
-- 
git-series 0.9.1

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply related

* Re: [PATCH 4/5] arm64: dts: meson-sm1-sei610: add HDMI display support
From: Neil Armstrong @ 2019-08-22  8:23 UTC (permalink / raw)
  To: Kevin Hilman, ulf.hansson
  Cc: linux-amlogic, linux-kernel, linux-arm-kernel, linux-pm
In-Reply-To: <7ho90i5c41.fsf@baylibre.com>

On 22/08/2019 01:31, Kevin Hilman wrote:
> Neil Armstrong <narmstrong@baylibre.com> writes:
> 
>> Update compatible of the pwc-vpu node and add the HDMI support nodes
>> for the Amlogic SM1 Based SEI610 Board.
> 
> I think this changelog is out of date.  It's not doing anything with the
> VPU pwrc node.

Exact, thanks for pointing it

> 
> Kevin
> 
>> Signed-off-by: Neil Armstrong <narmstrong@baylibre.com>
>> ---
>>  .../boot/dts/amlogic/meson-sm1-sei610.dts     | 23 +++++++++++++++++++
>>  1 file changed, 23 insertions(+)
>>
>> diff --git a/arch/arm64/boot/dts/amlogic/meson-sm1-sei610.dts b/arch/arm64/boot/dts/amlogic/meson-sm1-sei610.dts
>> index 12dab0ba2f26..66bd3bfbaf91 100644
>> --- a/arch/arm64/boot/dts/amlogic/meson-sm1-sei610.dts
>> +++ b/arch/arm64/boot/dts/amlogic/meson-sm1-sei610.dts
>> @@ -51,6 +51,17 @@
>>  		};
>>  	};
>>  
>> +	hdmi-connector {
>> +		compatible = "hdmi-connector";
>> +		type = "a";
>> +
>> +		port {
>> +			hdmi_connector_in: endpoint {
>> +				remote-endpoint = <&hdmi_tx_tmds_out>;
>> +			};
>> +		};
>> +	};
>> +
>>  	leds {
>>  		compatible = "gpio-leds";
>>  
>> @@ -177,6 +188,18 @@
>>  	phy-mode = "rmii";
>>  };
>>  
>> +&hdmi_tx {
>> +	status = "okay";
>> +	pinctrl-0 = <&hdmitx_hpd_pins>, <&hdmitx_ddc_pins>;
>> +	pinctrl-names = "default";
>> +};
>> +
>> +&hdmi_tx_tmds_port {
>> +	hdmi_tx_tmds_out: endpoint {
>> +		remote-endpoint = <&hdmi_connector_in>;
>> +	};
>> +};
>> +
>>  &i2c3 {
>>  	status = "okay";
>>  	pinctrl-0 = <&i2c3_sda_a_pins>, <&i2c3_sck_a_pins>;
>> -- 
>> 2.22.0


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply

* Re: [PATCH RESEND] i2c: mediatek: disable zero-length transfers for mt8183
From: Yingjoe Chen @ 2019-08-22  8:24 UTC (permalink / raw)
  To: Hsin-Yi Wang
  Cc: Nicolas Boichat, Qii Wang, Alexandru M Stan, Wolfram Sang,
	Jun Gao, linux-kernel, linux-mediatek, linux-i2c,
	Matthias Brugger, Thomas Gleixner, linux-arm-kernel
In-Reply-To: <20190822055737.142384-1-hsinyi@chromium.org>

On Thu, 2019-08-22 at 13:57 +0800, Hsin-Yi Wang wrote:
> When doing i2cdetect quick write mode, we would get transfer
> error ENOMEM, and i2cdetect shows there's no device at the address.
> Quoting from mt8183 datasheet, the number of transfers to be
> transferred in one transaction should be set to bigger than 1,
> so we should forbid zero-length transfer and update functionality.


<...>

> @@ -933,8 +942,8 @@ static int mtk_i2c_probe(struct platform_device *pdev)
>  	i2c->dev = &pdev->dev;
>  	i2c->adap.dev.parent = &pdev->dev;
>  	i2c->adap.owner = THIS_MODULE;
> -	i2c->adap.algo = &mtk_i2c_algorithm;
>  	i2c->adap.quirks = i2c->dev_comp->quirks;
> +	i2c->adap.algo = &mtk_i2c_algorithm;
>  	i2c->adap.timeout = 2 * HZ;
>  	i2c->adap.retries = 1;
>  

Why do you need to change this part?

Joe.C




_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply

* Re: [PATCH 4/4] misc: xilinx_sdfec: Prevent integer overflow in xsdfec_table_write()
From: Michal Simek @ 2019-08-22  8:27 UTC (permalink / raw)
  To: Dan Carpenter, Derek Kiernan, Dragan Cvetic
  Cc: Arnd Bergmann, Greg Kroah-Hartman, kernel-janitors, Michal Simek,
	linux-kernel, linux-arm-kernel
In-Reply-To: <20190821071122.GD26957@mwanda>

On 21. 08. 19 9:11, Dan Carpenter wrote:
> The checking here needs to handle integer overflows because "offset" and
> "len" come from the user.
> 
> Fixes: 20ec628e8007 ("misc: xilinx_sdfec: Add ability to configure LDPC")
> Signed-off-by: Dan Carpenter <dan.carpenter@oracle.com>
> ---
>  drivers/misc/xilinx_sdfec.c | 4 +++-
>  1 file changed, 3 insertions(+), 1 deletion(-)
> 
> diff --git a/drivers/misc/xilinx_sdfec.c b/drivers/misc/xilinx_sdfec.c
> index 3fc53d20abf3..0bf3bcc8e1ef 100644
> --- a/drivers/misc/xilinx_sdfec.c
> +++ b/drivers/misc/xilinx_sdfec.c
> @@ -611,7 +611,9 @@ static int xsdfec_table_write(struct xsdfec_dev *xsdfec, u32 offset,
>  	 * Writes that go beyond the length of
>  	 * Shared Scale(SC) table should fail
>  	 */
> -	if ((XSDFEC_REG_WIDTH_JUMP * (offset + len)) > depth) {
> +	if (offset > depth / XSDFEC_REG_WIDTH_JUMP ||
> +	    len > depth / XSDFEC_REG_WIDTH_JUMP ||
> +	    offset + len > depth / XSDFEC_REG_WIDTH_JUMP) {
>  		dev_dbg(xsdfec->dev, "Write exceeds SC table length");
>  		return -EINVAL;
>  	}
> 

Reviewed-by: Michal Simek <michal.simek@xilinx.com>

Thanks,
Michal

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply

* Re: [PATCH 1/4] misc: xilinx_sdfec: Fix a couple small information leaks
From: Dan Carpenter @ 2019-08-22  8:28 UTC (permalink / raw)
  To: Michal Simek
  Cc: Arnd Bergmann, Greg Kroah-Hartman, Dragan Cvetic, kernel-janitors,
	linux-kernel, Derek Kiernan, linux-arm-kernel
In-Reply-To: <58e9a151-3d92-c730-eea6-5cfde90934a4@xilinx.com>

On Thu, Aug 22, 2019 at 10:14:12AM +0200, Michal Simek wrote:
> Hi Dan,
> 
> On 21. 08. 19 9:06, Dan Carpenter wrote:
> > These structs have holes in them so we end up disclosing a few bytes of
> > uninitialized stack data.
> > 
> > drivers/misc/xilinx_sdfec.c:305 xsdfec_get_status() warn: check that 'status' doesn't leak information (struct has a hole after 'activity')
> > drivers/misc/xilinx_sdfec.c:449 xsdfec_get_turbo() warn: check that 'turbo_params' doesn't leak information (struct has a hole after 'scale')
> 
> Who is generating these warnings? Is this any new GCC or different tool?
> I see that 3byte padding but never seen these warnings.

This is a Smatch check.

regards,
dan carpenter


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply

* [PATCH 2/4 v2] misc: xilinx_sdfec: Return -EFAULT if copy_from_user() fails
From: Dan Carpenter @ 2019-08-22  8:31 UTC (permalink / raw)
  To: Derek Kiernan, Dragan Cvetic
  Cc: Arnd Bergmann, Greg Kroah-Hartman, kernel-janitors, Michal Simek,
	linux-kernel, linux-arm-kernel
In-Reply-To: <20190821070702.GB26957@mwanda>

The copy_from_user() function returns the number of bytes remaining to
be copied but we want to return -EFAULT to the user.

Fixes: 20ec628e8007 ("misc: xilinx_sdfec: Add ability to configure LDPC")
Signed-off-by: Dan Carpenter <dan.carpenter@oracle.com>
Reviewed-by: Michal Simek <michal.simek@xilinx.com>
---
v2: Fix a typo in the commit message.  funciton --> function

 drivers/misc/xilinx_sdfec.c | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)

diff --git a/drivers/misc/xilinx_sdfec.c b/drivers/misc/xilinx_sdfec.c
index dc1b8b412712..813b82c59360 100644
--- a/drivers/misc/xilinx_sdfec.c
+++ b/drivers/misc/xilinx_sdfec.c
@@ -651,9 +651,10 @@ static int xsdfec_add_ldpc(struct xsdfec_dev *xsdfec, void __user *arg)
 	if (!ldpc)
 		return -ENOMEM;
 
-	ret = copy_from_user(ldpc, arg, sizeof(*ldpc));
-	if (ret)
+	if (copy_from_user(ldpc, arg, sizeof(*ldpc))) {
+		ret = -EFAULT;
 		goto err_out;
+	}
 
 	if (xsdfec->config.code == XSDFEC_TURBO_CODE) {
 		ret = -EIO;
-- 
2.20.1

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply related

* [PATCH] net/wireless: Delete unnecessary checks before the macro call “dev_kfree_skb”
From: Markus Elfring @ 2019-08-22  8:30 UTC (permalink / raw)
  To: linux-wireless, linux-arm-kernel, linux-mediatek, ath10k,
	David S. Miller, Felix Fietkau, Kalle Valo, Lorenzo Bianconi,
	Matthias Brugger, Roy Luo, Ryder Lee, Solomon Peachy,
	Stanislaw Gruszka
  Cc: kernel-janitors, LKML

From: Markus Elfring <elfring@users.sourceforge.net>
Date: Thu, 22 Aug 2019 10:20:10 +0200

The dev_kfree_skb() function performs also input parameter validation.
Thus the test around the shown calls is not needed.

This issue was detected by using the Coccinelle software.

Signed-off-by: Markus Elfring <elfring@users.sourceforge.net>
---
 drivers/net/wireless/ath/ath10k/wmi.c               | 4 +---
 drivers/net/wireless/intel/iwlegacy/3945-mac.c      | 8 ++------
 drivers/net/wireless/intel/iwlegacy/common.c        | 8 ++------
 drivers/net/wireless/mediatek/mt76/mt76x02_beacon.c | 5 +----
 drivers/net/wireless/st/cw1200/scan.c               | 3 +--
 5 files changed, 7 insertions(+), 21 deletions(-)

diff --git a/drivers/net/wireless/ath/ath10k/wmi.c b/drivers/net/wireless/ath/ath10k/wmi.c
index 4f707c6394bb..d384293429b4 100644
--- a/drivers/net/wireless/ath/ath10k/wmi.c
+++ b/drivers/net/wireless/ath/ath10k/wmi.c
@@ -9440,7 +9440,5 @@ void ath10k_wmi_detach(struct ath10k *ar)
 	}

 	cancel_work_sync(&ar->svc_rdy_work);
-
-	if (ar->svc_rdy_skb)
-		dev_kfree_skb(ar->svc_rdy_skb);
+	dev_kfree_skb(ar->svc_rdy_skb);
 }
diff --git a/drivers/net/wireless/intel/iwlegacy/3945-mac.c b/drivers/net/wireless/intel/iwlegacy/3945-mac.c
index b82da75a9ae3..4b3b166f6f2a 100644
--- a/drivers/net/wireless/intel/iwlegacy/3945-mac.c
+++ b/drivers/net/wireless/intel/iwlegacy/3945-mac.c
@@ -2302,9 +2302,7 @@ __il3945_down(struct il_priv *il)
 	il3945_hw_txq_ctx_free(il);
 exit:
 	memset(&il->card_alive, 0, sizeof(struct il_alive_resp));
-
-	if (il->beacon_skb)
-		dev_kfree_skb(il->beacon_skb);
+	dev_kfree_skb(il->beacon_skb);
 	il->beacon_skb = NULL;

 	/* clear out any free frames */
@@ -3847,9 +3845,7 @@ il3945_pci_remove(struct pci_dev *pdev)
 	il_free_channel_map(il);
 	il_free_geos(il);
 	kfree(il->scan_cmd);
-	if (il->beacon_skb)
-		dev_kfree_skb(il->beacon_skb);
-
+	dev_kfree_skb(il->beacon_skb);
 	ieee80211_free_hw(il->hw);
 }

diff --git a/drivers/net/wireless/intel/iwlegacy/common.c b/drivers/net/wireless/intel/iwlegacy/common.c
index 73f7bbf742bc..4e7e64f46ea8 100644
--- a/drivers/net/wireless/intel/iwlegacy/common.c
+++ b/drivers/net/wireless/intel/iwlegacy/common.c
@@ -5182,8 +5182,7 @@ il_mac_reset_tsf(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
 	memset(&il->current_ht_config, 0, sizeof(struct il_ht_config));

 	/* new association get rid of ibss beacon skb */
-	if (il->beacon_skb)
-		dev_kfree_skb(il->beacon_skb);
+	dev_kfree_skb(il->beacon_skb);
 	il->beacon_skb = NULL;
 	il->timestamp = 0;

@@ -5302,10 +5301,7 @@ il_beacon_update(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
 	}

 	spin_lock_irqsave(&il->lock, flags);
-
-	if (il->beacon_skb)
-		dev_kfree_skb(il->beacon_skb);
-
+	dev_kfree_skb(il->beacon_skb);
 	il->beacon_skb = skb;

 	timestamp = ((struct ieee80211_mgmt *)skb->data)->u.beacon.timestamp;
diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_beacon.c b/drivers/net/wireless/mediatek/mt76/mt76x02_beacon.c
index d61c686e08de..d6487cd67cca 100644
--- a/drivers/net/wireless/mediatek/mt76/mt76x02_beacon.c
+++ b/drivers/net/wireless/mediatek/mt76/mt76x02_beacon.c
@@ -88,10 +88,7 @@ int mt76x02_mac_set_beacon(struct mt76x02_dev *dev, u8 vif_idx,
 	for (i = 0; i < ARRAY_SIZE(dev->beacons); i++) {
 		if (vif_idx == i) {
 			force_update = !!dev->beacons[i] ^ !!skb;
-
-			if (dev->beacons[i])
-				dev_kfree_skb(dev->beacons[i]);
-
+			dev_kfree_skb(dev->beacons[i]);
 			dev->beacons[i] = skb;
 			__mt76x02_mac_set_beacon(dev, bcn_idx, skb);
 		} else if (force_update && dev->beacons[i]) {
diff --git a/drivers/net/wireless/st/cw1200/scan.c b/drivers/net/wireless/st/cw1200/scan.c
index c46b044b7f7b..988581cc134b 100644
--- a/drivers/net/wireless/st/cw1200/scan.c
+++ b/drivers/net/wireless/st/cw1200/scan.c
@@ -120,8 +120,7 @@ int cw1200_hw_scan(struct ieee80211_hw *hw,
 		++priv->scan.n_ssids;
 	}

-	if (frame.skb)
-		dev_kfree_skb(frame.skb);
+	dev_kfree_skb(frame.skb);
 	mutex_unlock(&priv->conf_mutex);
 	queue_work(priv->workqueue, &priv->scan.work);
 	return 0;
--
2.23.0


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply related

* Re: [PATCH 2/5] soc: amlogic: Add support for Everything-Else power domains controller
From: Neil Armstrong @ 2019-08-22  8:35 UTC (permalink / raw)
  To: Kevin Hilman, ulf.hansson
  Cc: linux-amlogic, linux-kernel, linux-arm-kernel, linux-pm
In-Reply-To: <7hzhk25ct3.fsf@baylibre.com>

On 22/08/2019 01:16, Kevin Hilman wrote:
> Neil Armstrong <narmstrong@baylibre.com> writes:
> 
>> Add support for the General Purpose Amlogic Everything-Else Power controller,
>> with the first support for G12A and SM1 SoCs dedicated to the VPU, PCIe,
>> USB, NNA, GE2D and Ethernet Power Domains.
>>
>> Signed-off-by: Neil Armstrong <narmstrong@baylibre.com>
> 
> Nice!  Thanks for generalizing this.
> 
> A few comments/concerns below, but this is mostly ready.
> 
>> ---
>>  drivers/soc/amlogic/Kconfig         |  11 +
>>  drivers/soc/amlogic/Makefile        |   1 +
>>  drivers/soc/amlogic/meson-ee-pwrc.c | 560 ++++++++++++++++++++++++++++
>>  3 files changed, 572 insertions(+)
>>  create mode 100644 drivers/soc/amlogic/meson-ee-pwrc.c
>>
>> diff --git a/drivers/soc/amlogic/Kconfig b/drivers/soc/amlogic/Kconfig
>> index 23bfb8ef4fdb..bc2c912949bd 100644
>> --- a/drivers/soc/amlogic/Kconfig
>> +++ b/drivers/soc/amlogic/Kconfig
>> @@ -37,6 +37,17 @@ config MESON_GX_PM_DOMAINS
>>  	  Say yes to expose Amlogic Meson GX Power Domains as
>>  	  Generic Power Domains.
>>  
>> +config MESON_EE_PM_DOMAINS
>> +	bool "Amlogic Meson Everything-Else Power Domains driver"
>> +	depends on ARCH_MESON || COMPILE_TEST
>> +	depends on PM && OF
>> +	default ARCH_MESON
>> +	select PM_GENERIC_DOMAINS
>> +	select PM_GENERIC_DOMAINS_OF
>> +	help
>> +	  Say yes to expose Amlogic Meson Everything-Else Power Domains as
>> +	  Generic Power Domains.
>> +
>>  config MESON_MX_SOCINFO
>>  	bool "Amlogic Meson MX SoC Information driver"
>>  	depends on ARCH_MESON || COMPILE_TEST
>> diff --git a/drivers/soc/amlogic/Makefile b/drivers/soc/amlogic/Makefile
>> index f2e4ed171297..de79d044b545 100644
>> --- a/drivers/soc/amlogic/Makefile
>> +++ b/drivers/soc/amlogic/Makefile
>> @@ -4,3 +4,4 @@ obj-$(CONFIG_MESON_CLK_MEASURE) += meson-clk-measure.o
>>  obj-$(CONFIG_MESON_GX_SOCINFO) += meson-gx-socinfo.o
>>  obj-$(CONFIG_MESON_GX_PM_DOMAINS) += meson-gx-pwrc-vpu.o
>>  obj-$(CONFIG_MESON_MX_SOCINFO) += meson-mx-socinfo.o
>> +obj-$(CONFIG_MESON_EE_PM_DOMAINS) += meson-ee-pwrc.o
>> diff --git a/drivers/soc/amlogic/meson-ee-pwrc.c b/drivers/soc/amlogic/meson-ee-pwrc.c
>> new file mode 100644
>> index 000000000000..7159888c850b
>> --- /dev/null
>> +++ b/drivers/soc/amlogic/meson-ee-pwrc.c
>> @@ -0,0 +1,560 @@
>> +// SPDX-License-Identifier: GPL-2.0+
>> +/*
>> + * Copyright (c) 2019 BayLibre, SAS
>> + * Author: Neil Armstrong <narmstrong@baylibre.com>
>> + */
>> +
>> +#include <linux/of_address.h>
>> +#include <linux/platform_device.h>
>> +#include <linux/pm_domain.h>
>> +#include <linux/bitfield.h>
>> +#include <linux/regmap.h>
>> +#include <linux/mfd/syscon.h>
>> +#include <linux/of_device.h>
>> +#include <linux/reset-controller.h>
>> +#include <linux/reset.h>
>> +#include <linux/clk.h>
>> +#include <dt-bindings/power/meson-g12a-power.h>
>> +#include <dt-bindings/power/meson-sm1-power.h>
>> +
>> +/* AO Offsets */
>> +
>> +#define AO_RTI_GEN_PWR_SLEEP0		(0x3a << 2)
>> +#define AO_RTI_GEN_PWR_ISO0		(0x3b << 2)
>> +
>> +/* HHI Offsets */
>> +
>> +#define HHI_MEM_PD_REG0			(0x40 << 2)
>> +#define HHI_VPU_MEM_PD_REG0		(0x41 << 2)
>> +#define HHI_VPU_MEM_PD_REG1		(0x42 << 2)
>> +#define HHI_VPU_MEM_PD_REG3		(0x43 << 2)
>> +#define HHI_VPU_MEM_PD_REG4		(0x44 << 2)
>> +#define HHI_AUDIO_MEM_PD_REG0		(0x45 << 2)
>> +#define HHI_NANOQ_MEM_PD_REG0		(0x46 << 2)
>> +#define HHI_NANOQ_MEM_PD_REG1		(0x47 << 2)
>> +#define HHI_VPU_MEM_PD_REG2		(0x4d << 2)
>> +
>> +struct meson_ee_pwrc;
>> +struct meson_ee_pwrc_domain;
>> +
>> +struct meson_ee_pwrc_mem_domain {
>> +	unsigned int reg;
>> +	unsigned int mask;
>> +};
>> +
>> +struct meson_ee_pwrc_top_domain {
>> +	unsigned int sleep_reg;
>> +	unsigned int sleep_mask;
>> +	unsigned int iso_reg;
>> +	unsigned int iso_mask;
>> +};
>> +
>> +struct meson_ee_pwrc_domain_desc {
>> +	char *name;
>> +	char **reset_names;
>> +	unsigned int reset_names_count;
>> +	char **clk_names;
>> +	unsigned int clk_names_count;
>> +	struct meson_ee_pwrc_top_domain *top_pd;
>> +	unsigned int mem_pd_count;
>> +	struct meson_ee_pwrc_mem_domain *mem_pd;
>> +	bool (*get_power)(struct meson_ee_pwrc_domain *pwrc_domain);
>> +};
>> +
>> +struct meson_ee_pwrc_domain_data {
>> +	unsigned int count;
>> +	struct meson_ee_pwrc_domain_desc *domains;
>> +};
>> +
>> +/* Clock and Resets lists */
>> +
>> +static char *g12a_pwrc_vpu_resets[] = {
>> +	"viu", "venc", "vcbus", "bt656",
>> +	"rdma", "venci", "vencp", "vdac",
>> +	"vdi6", "vencl", "vid_lock",
>> +};
>> +
>> +static char *g12a_pwrc_vpu_clks[] = {
>> +	"vpu", "vapb",
>> +};
>> +
>> +/* TOP Power Domains */
>> +
>> +static struct meson_ee_pwrc_top_domain g12a_pwrc_vpu = {
>> +	.sleep_reg = AO_RTI_GEN_PWR_SLEEP0,
>> +	.sleep_mask = BIT(8),
>> +	.iso_reg = AO_RTI_GEN_PWR_SLEEP0,
>> +	.iso_mask = BIT(9),
>> +};
>> +
>> +#define SM1_EE_PD(__bit)					\
>> +	{							\
>> +		.sleep_reg = AO_RTI_GEN_PWR_SLEEP0, 		\
>> +		.sleep_mask = BIT(__bit), 			\
>> +		.iso_reg = AO_RTI_GEN_PWR_ISO0, 		\
>> +		.iso_mask = BIT(__bit), 			\
>> +	}
>> +
>> +static struct meson_ee_pwrc_top_domain sm1_pwrc_vpu = SM1_EE_PD(8);
>> +static struct meson_ee_pwrc_top_domain sm1_pwrc_nna = SM1_EE_PD(16);
>> +static struct meson_ee_pwrc_top_domain sm1_pwrc_usb = SM1_EE_PD(17);
>> +static struct meson_ee_pwrc_top_domain sm1_pwrc_pci = SM1_EE_PD(18);
>> +static struct meson_ee_pwrc_top_domain sm1_pwrc_ge2d = SM1_EE_PD(19);
>> +
>> +/* Memory PD Domains */
>> +
>> +#define VPU_MEMPD(__reg)					\
>> +	{ __reg, GENMASK(1, 0) },				\
>> +	{ __reg, GENMASK(3, 2) },				\
>> +	{ __reg, GENMASK(5, 4) },				\
>> +	{ __reg, GENMASK(7, 6) },				\
>> +	{ __reg, GENMASK(9, 8) },				\
>> +	{ __reg, GENMASK(11, 10) },				\
>> +	{ __reg, GENMASK(13, 12) },				\
>> +	{ __reg, GENMASK(15, 14) },				\
>> +	{ __reg, GENMASK(17, 16) },				\
>> +	{ __reg, GENMASK(19, 18) },				\
>> +	{ __reg, GENMASK(21, 20) },				\
>> +	{ __reg, GENMASK(23, 22) },				\
>> +	{ __reg, GENMASK(25, 24) },				\
>> +	{ __reg, GENMASK(27, 26) },				\
>> +	{ __reg, GENMASK(29, 28) },				\
>> +	{ __reg, GENMASK(31, 30) }
>> +
>> +#define VPU_HHI_MEMPD(__reg)					\
>> +	{ __reg, BIT(8) },					\
>> +	{ __reg, BIT(9) },					\
>> +	{ __reg, BIT(10) },					\
>> +	{ __reg, BIT(11) },					\
>> +	{ __reg, BIT(12) },					\
>> +	{ __reg, BIT(13) },					\
>> +	{ __reg, BIT(14) },					\
>> +	{ __reg, BIT(15) }
>> +
>> +static struct meson_ee_pwrc_mem_domain g12a_pwrc_mem_vpu[] = {
>> +	VPU_MEMPD(HHI_VPU_MEM_PD_REG0),
>> +	VPU_MEMPD(HHI_VPU_MEM_PD_REG1),
>> +	VPU_MEMPD(HHI_VPU_MEM_PD_REG2),
>> +	VPU_HHI_MEMPD(HHI_MEM_PD_REG0),
>> +};
>> +
>> +static struct meson_ee_pwrc_mem_domain g12a_pwrc_mem_eth[] = {
>> +	{ HHI_MEM_PD_REG0, GENMASK(3, 2) },
>> +};
>> +
>> +static struct meson_ee_pwrc_mem_domain sm1_pwrc_mem_vpu[] = {
>> +	VPU_MEMPD(HHI_VPU_MEM_PD_REG0),
>> +	VPU_MEMPD(HHI_VPU_MEM_PD_REG1),
>> +	VPU_MEMPD(HHI_VPU_MEM_PD_REG2),
>> +	VPU_MEMPD(HHI_VPU_MEM_PD_REG3),
>> +	{ HHI_VPU_MEM_PD_REG4, GENMASK(1, 0) },
>> +	{ HHI_VPU_MEM_PD_REG4, GENMASK(3, 2) },
>> +	{ HHI_VPU_MEM_PD_REG4, GENMASK(5, 4) },
>> +	{ HHI_VPU_MEM_PD_REG4, GENMASK(7, 6) },
>> +	VPU_HHI_MEMPD(HHI_MEM_PD_REG0),
>> +};
>> +
>> +static struct meson_ee_pwrc_mem_domain sm1_pwrc_mem_nna[] = {
>> +	{ HHI_NANOQ_MEM_PD_REG0, 0xff },
>> +	{ HHI_NANOQ_MEM_PD_REG1, 0xff },
>> +};
>> +
>> +static struct meson_ee_pwrc_mem_domain sm1_pwrc_mem_usb[] = {
>> +	{ HHI_MEM_PD_REG0, GENMASK(31, 30) },
>> +};
>> +
>> +static struct meson_ee_pwrc_mem_domain sm1_pwrc_mem_pcie[] = {
>> +	{ HHI_MEM_PD_REG0, GENMASK(29, 26) },
>> +};
>> +
>> +static struct meson_ee_pwrc_mem_domain sm1_pwrc_mem_ge2d[] = {
>> +	{ HHI_MEM_PD_REG0, GENMASK(25, 18) },
>> +};
>> +
>> +static struct meson_ee_pwrc_mem_domain sm1_pwrc_mem_audio[] = {
>> +	{ HHI_MEM_PD_REG0, GENMASK(5, 4) },
>> +	{ HHI_AUDIO_MEM_PD_REG0, GENMASK(1, 0) },
>> +	{ HHI_AUDIO_MEM_PD_REG0, GENMASK(3, 2) },
>> +	{ HHI_AUDIO_MEM_PD_REG0, GENMASK(5, 4) },
>> +	{ HHI_AUDIO_MEM_PD_REG0, GENMASK(7, 6) },
>> +	{ HHI_AUDIO_MEM_PD_REG0, GENMASK(13, 12) },
>> +	{ HHI_AUDIO_MEM_PD_REG0, GENMASK(15, 14) },
>> +	{ HHI_AUDIO_MEM_PD_REG0, GENMASK(17, 16) },
>> +	{ HHI_AUDIO_MEM_PD_REG0, GENMASK(19, 18) },
>> +	{ HHI_AUDIO_MEM_PD_REG0, GENMASK(21, 20) },
>> +	{ HHI_AUDIO_MEM_PD_REG0, GENMASK(23, 22) },
>> +	{ HHI_AUDIO_MEM_PD_REG0, GENMASK(25, 24) },
>> +	{ HHI_AUDIO_MEM_PD_REG0, GENMASK(27, 26) },
>> +};
>> +
>> +#define VPU_PD(__name, __resets, __clks, __top_pd, __mem, __get_power)	\
>> +	{								\
>> +		.name = __name,						\
>> +		.reset_names_count = ARRAY_SIZE(__resets),		\
>> +		.reset_names = __resets,				\
>> +		.clk_names_count = ARRAY_SIZE(__clks),			\
>> +		.clk_names = __clks,					\
>> +		.top_pd = __top_pd,					\
>> +		.mem_pd_count = ARRAY_SIZE(__mem),			\
>> +		.mem_pd = __mem,					\
>> +		.get_power = __get_power,				\
>> +	}
>> +
>> +#define TOP_PD(__name, __top_pd, __mem)					\
>> +	{								\
>> +		.name = __name,						\
>> +		.top_pd = __top_pd,					\
>> +		.mem_pd_count = ARRAY_SIZE(__mem),			\
>> +		.mem_pd = __mem,					\
>> +	}
> 
> Why can't the TOP_PD domains also have a __get_power().  Shouldn't we
> just be able to check the sleep_reg/sleep_mask like in the VPU case?

It can, I can add it later, do we need it for this version ?

> 
> Also, for readability, I think the arguments to VPU_PD and TOP_PD to
> have the same order, at least for the common ones.  IOW, __name,
> __top_pd, __mem should be first.

Sure, will fix

> 
>> +#define MEM_PD(__name, __mem)						\
>> +	TOP_PD(__name, NULL, __mem)
>> +
>> +static bool pwrc_vpu_get_power(struct meson_ee_pwrc_domain *pwrc_domain);
>> +
>> +static struct meson_ee_pwrc_domain_desc g12a_pwrc_domains[] = {
>> +	[PWRC_G12A_VPU_ID]  = VPU_PD("VPU", g12a_pwrc_vpu_resets,
>> +				     g12a_pwrc_vpu_clks, &g12a_pwrc_vpu,
>> +				     g12a_pwrc_mem_vpu,
>> +				     pwrc_vpu_get_power),
>> +	[PWRC_G12A_ETH_ID] = MEM_PD("ETH", g12a_pwrc_mem_eth),
>> +};
>> +
>> +static struct meson_ee_pwrc_domain_desc sm1_pwrc_domains[] = {
>> +	[PWRC_SM1_VPU_ID]  = VPU_PD("VPU", g12a_pwrc_vpu_resets,
>> +				    g12a_pwrc_vpu_clks, &sm1_pwrc_vpu,
>> +				    sm1_pwrc_mem_vpu,
>> +				    pwrc_vpu_get_power),
>> +	[PWRC_SM1_NNA_ID]  = TOP_PD("NNA", &sm1_pwrc_nna, sm1_pwrc_mem_nna),
>> +	[PWRC_SM1_USB_ID]  = TOP_PD("USB", &sm1_pwrc_usb, sm1_pwrc_mem_usb),
>> +	[PWRC_SM1_PCIE_ID] = TOP_PD("PCI", &sm1_pwrc_pci, sm1_pwrc_mem_pcie),
>> +	[PWRC_SM1_GE2D_ID] = TOP_PD("GE2D", &sm1_pwrc_ge2d, sm1_pwrc_mem_ge2d),
>> +	[PWRC_SM1_AUDIO_ID] = MEM_PD("AUDIO", sm1_pwrc_mem_audio),
>> +	[PWRC_SM1_ETH_ID] = MEM_PD("ETH", g12a_pwrc_mem_eth),
>> +};
>> +
>> +struct meson_ee_pwrc_domain {
>> +	struct generic_pm_domain base;
>> +	bool enabled;
>> +	struct meson_ee_pwrc *pwrc;
>> +	struct meson_ee_pwrc_domain_desc desc;
>> +	struct clk **clks;
>> +	int num_clks;
>> +	struct reset_control **rstc;
>> +	int num_rstc;
>> +};
>> +
>> +struct meson_ee_pwrc {
>> +	struct regmap *regmap_ao;
>> +	struct regmap *regmap_hhi;
>> +	struct meson_ee_pwrc_domain *domains;
>> +	struct genpd_onecell_data xlate;
>> +};
>> +
>> +static bool pwrc_vpu_get_power(struct meson_ee_pwrc_domain *pwrc_domain)
>> +{
>> +	u32 reg;
>> +
>> +	regmap_read(pwrc_domain->pwrc->regmap_ao,
>> +		    pwrc_domain->desc.top_pd->sleep_reg, &reg);
>> +
>> +	return (reg & pwrc_domain->desc.top_pd->sleep_mask);
>> +}
>> +
>> +static int meson_ee_reset_assert(struct meson_ee_pwrc_domain *pwrc_domain)
>> +{
>> +	int i, ret;
>> +
>> +	for (i = 0 ; i < pwrc_domain->num_rstc ; ++i) {
>> +		ret = reset_control_assert(pwrc_domain->rstc[i]);
>> +		if (ret)
>> +			return ret;
>> +	}
>> +
>> +	return 0;
>> +}
>> +
>> +static int meson_ee_reset_deassert(struct meson_ee_pwrc_domain *pwrc_domain)
>> +{
>> +	int i, ret;
>> +
>> +	for (i = 0 ; i < pwrc_domain->num_rstc ; ++i) {
>> +		ret = reset_control_deassert(pwrc_domain->rstc[i]);
>> +		if (ret)
>> +			return ret;
>> +	}
>> +
>> +	return 0;
>> +}
> 
> You should use the reset_array functions, then you don't need these helpers.
> 
>> +static int meson_ee_clk_disable(struct meson_ee_pwrc_domain *pwrc_domain)
>> +{
>> +	int i;
>> +
>> +	for (i = 0 ; i < pwrc_domain->num_clks ; ++i)
>> +		clk_disable(pwrc_domain->clks[i]);
>> +
>> +	for (i = 0 ; i < pwrc_domain->num_clks ; ++i)
>> +		clk_unprepare(pwrc_domain->clks[i]);
>> +
>> +	return 0;
>> +}
>> +
>> +static int meson_ee_clk_enable(struct meson_ee_pwrc_domain *pwrc_domain)
>> +{
>> +	int i, ret;
>> +
>> +	for (i = 0 ; i < pwrc_domain->num_clks ; ++i) {
>> +		ret = clk_prepare(pwrc_domain->clks[i]);
>> +		if (ret)
>> +			goto fail_prepare;
>> +	}
>> +
>> +	for (i = 0 ; i < pwrc_domain->num_clks ; ++i) {
>> +		ret = clk_enable(pwrc_domain->clks[i]);
>> +		if (ret)
>> +			goto fail_enable;
>> +	}
>> +
>> +	return 0;
>> +fail_enable:
>> +	while (--i)
>> +		clk_disable(pwrc_domain->clks[i]);
>> +
>> +	/* Unprepare all clocks */
>> +	i = pwrc_domain->num_clks;
>> +
>> +fail_prepare:
>> +	while (--i)
>> +		clk_unprepare(pwrc_domain->clks[i]);
>> +
>> +	return ret;
>> +}
> 
> Both the clk enable and disable functions above are just open-coding of
> the clk_bulk equivalents.  Please use clk_bulk_*, then you don't need
> these helpers.  (c.f. the RFT patch I did to convert the old driver to
> clk_bulk[1])

Yes, but clk_bulk takes _all_ the clocks from the node, you canot specify
a list of names, maybe it's overengineered but I wanted to specify the
exact resets and clocks for each power domain, clk_bulk doesn't provide this.

> 
>> +static int meson_ee_pwrc_off(struct generic_pm_domain *domain)
>> +{
>> +	struct meson_ee_pwrc_domain *pwrc_domain =
>> +		container_of(domain, struct meson_ee_pwrc_domain, base);
>> +	int i;
>> +
>> +	if (pwrc_domain->desc.top_pd)
>> +		regmap_update_bits(pwrc_domain->pwrc->regmap_ao,
>> +				   pwrc_domain->desc.top_pd->sleep_reg,
>> +				   pwrc_domain->desc.top_pd->sleep_mask,
>> +				   pwrc_domain->desc.top_pd->sleep_mask);
>> +	udelay(20);
>> +
>> +	for (i = 0 ; i < pwrc_domain->desc.mem_pd_count ; ++i)
>> +		regmap_update_bits(pwrc_domain->pwrc->regmap_hhi,
>> +				   pwrc_domain->desc.mem_pd[i].reg,
>> +				   pwrc_domain->desc.mem_pd[i].mask,
>> +				   pwrc_domain->desc.mem_pd[i].mask);
>> +
>> +	udelay(20);
>> +
>> +	if (pwrc_domain->desc.top_pd)
>> +		regmap_update_bits(pwrc_domain->pwrc->regmap_ao,
>> +				   pwrc_domain->desc.top_pd->iso_reg,
>> +				   pwrc_domain->desc.top_pd->iso_mask,
>> +				   pwrc_domain->desc.top_pd->iso_mask);
>> +
>> +	if (pwrc_domain->num_clks) {
>> +		msleep(20);
>> +		meson_ee_clk_disable(pwrc_domain);
>> +	}
>> +
>> +	return 0;
>> +}
>> +
>> +static int meson_ee_pwrc_on(struct generic_pm_domain *domain)
>> +{
>> +	struct meson_ee_pwrc_domain *pwrc_domain =
>> +		container_of(domain, struct meson_ee_pwrc_domain, base);
>> +	int i, ret;
>> +
>> +	if (pwrc_domain->desc.top_pd)
>> +		regmap_update_bits(pwrc_domain->pwrc->regmap_ao,
>> +				   pwrc_domain->desc.top_pd->sleep_reg,
>> +				   pwrc_domain->desc.top_pd->sleep_mask, 0);
>> +	udelay(20);
>> +
>> +	for (i = 0 ; i < pwrc_domain->desc.mem_pd_count ; ++i)
>> +		regmap_update_bits(pwrc_domain->pwrc->regmap_hhi,
>> +				   pwrc_domain->desc.mem_pd[i].reg,
>> +				   pwrc_domain->desc.mem_pd[i].mask, 0);
>> +
>> +	udelay(20);
>> +
>> +	ret = meson_ee_reset_assert(pwrc_domain);
>> +	if (ret)
>> +		return ret;
>> +
>> +	if (pwrc_domain->desc.top_pd)
>> +		regmap_update_bits(pwrc_domain->pwrc->regmap_ao,
>> +				   pwrc_domain->desc.top_pd->iso_reg,
>> +				   pwrc_domain->desc.top_pd->iso_mask, 0);
>> +
>> +	ret = meson_ee_reset_deassert(pwrc_domain);
>> +	if (ret)
>> +		return ret;
>> +
>> +	return meson_ee_clk_enable(pwrc_domain);
>> +}
>> +
>> +static int meson_ee_pwrc_init_domain(struct platform_device *pdev,
>> +				     struct meson_ee_pwrc *sm1_pwrc,
>> +				     struct meson_ee_pwrc_domain *dom)
>> +{
>> +	dom->pwrc = sm1_pwrc;
>> +	dom->num_rstc = dom->desc.reset_names_count;
>> +	dom->num_clks = dom->desc.clk_names_count;
>> +
>> +	if (dom->num_rstc) {
>> +		int rst;
>> +
>> +		dom->rstc = devm_kcalloc(&pdev->dev, dom->num_rstc,
>> +				sizeof(struct reset_control *),	GFP_KERNEL);
>> +		if (!dom->rstc)
>> +			return -ENOMEM;
>> +
>> +		for (rst = 0 ; rst < dom->num_rstc ; ++rst) {
>> +			dom->rstc[rst] = devm_reset_control_get_exclusive(
>> +					&pdev->dev,
>> +					dom->desc.reset_names[rst]);
>> +			if (IS_ERR(dom->rstc[rst]))
>> +				return PTR_ERR(dom->rstc[rst]);
>> +		}
> 
> Why not simplify and use the helpers that get multiple reset lines (like
> devm_reset_control_array_get() used in meson-gx-pwrc-vpu.c)?

Same comment as clk_bulk, we cannot be sure we select the right reset lines.

> 
> You could also use reset_control_get_count() and compare to the expected
> number (dom->num_rstc).

This seems oversimplified

> 
>> +	}
>> +
>> +	if (dom->num_clks) {
>> +		int clk;
>> +
>> +		dom->clks = devm_kcalloc(&pdev->dev, dom->num_clks,
>> +				sizeof(struct clk *), GFP_KERNEL);
>> +		if (!dom->clks)
>> +			return -ENOMEM;
>> +
>> +		for (clk = 0 ; clk < dom->num_clks ; ++clk) {
>> +			dom->clks[clk] = devm_clk_get(&pdev->dev,
>> +					dom->desc.clk_names[clk]);
>> +			if (IS_ERR(dom->clks[clk]))
>> +				return PTR_ERR(dom->clks[clk]);
>> +		}
>> +	}
> 
> Please use clk_bulk API, and then just double-check that the number of
> clocks found matches the expected number.

Same, I'll either take all the clks and resets for the vpu power domain,
or keep this code to make sure we get the right clocks and resets.

> 
>> +	dom->base.name = dom->desc.name;
>> +	dom->base.power_on = meson_ee_pwrc_on;
>> +	dom->base.power_off = meson_ee_pwrc_off;
>> +
>> +	if (dom->desc.get_power) {
>> +		bool powered_off = dom->desc.get_power(dom);
> 
> nit: insert blank line here
> 
> More importantly, we defintely will have problem here in the
> !powered_off case.  TL;DR; the driver's state does not match the actual
> hardware state.
> 
> When powered_off = false, you're telling the genpd core that this domain
> is already turned on.  However, you haven't called _pwrc_on() yet for
> the domain, which means internal state of the driver for this domain
> (e.g. clock enables, resets, etc.) is not in sync with the HW.  On
> SEI610 this case is happending for the VPU, which seems to be enabled by
> u-boot, so this driver detects it as already on, which is fine.  But...
> 
> Remember that the ->power_off() function will be called during suspend,
> and will lead to the clk unprepare/disable calls.  However, for domains
> that are detected as on (!powered_off), clk prepare/enable will never
> have been called, so that when suspend happens, you'll get "already
> unprepared" errors from the clock core
> 
> IOW, I think you need something like this here:
> 
> 		if (!powered_off)
> 			meson_ee_pwrc_on(&dom->base);
> 
> so that the internal state of clock fwk etc. matches the detected state
> of the HW.  The problem with that simple fix, at least for the VPU is
> that it might cause us to lose any existing display or framebuffer
> console that's on-going.  Probably needs some testing.

Yes, I forgot to take the _shutdown() function from gx_pwrc_vpu driver :

349 static void meson_gx_pwrc_vpu_shutdown(struct platform_device *pdev)
350 {
351         struct meson_gx_pwrc_vpu *vpu_pd = platform_get_drvdata(pdev);
352         bool powered_off;
353
354         powered_off = meson_gx_pwrc_vpu_get_power(vpu_pd);
355         if (!powered_off)
356                 vpu_pd->genpd.power_off(&vpu_pd->genpd);
357 }

> 
> Anyways, to see what I mean, try suspend/resume (you can test this
> series on my integ branch with "rtcwake -d rtc0 -m mem -s4") and you'll
> see error splats from the clock core during suspend.
> 
> 
> 
>> +		pm_genpd_init(&dom->base, &pm_domain_always_on_gov,
>> +			      powered_off);
> 
>> +	} else
>> +		pm_genpd_init(&dom->base, NULL, true);
> 
> nit: the else clause should also have {} to match the if
> (c.f. CodingStyle)

OK

> 
> Why do you force the always-on governor in the case where ->get_power()
> exists, but not the other?
> 
> If you force that, then for any devices connected to these domains that
> use runtime PM, they will never turn off the domain when it's idle.
> IOW, these domains will only ever be turned off on system-wide
> suspend/resume.
> 
> IMO, unless there's a good reason not to, you should pass NULL for the
> governor.

It's for legacy when VPU is initialized from vendor U-Boot, look at commit :
339cd0ea082287ea8e2b7e7159a5a33665a2cbe3 "soc: amlogic: meson-gx-pwrc-vpu: fix power-off when powered by bootloader"

    In the case the VPU power domain has been powered on by the bootloader
    and no driver are attached to this power domain, the genpd will power it
    off after a certain amount of time, but the clocks hasn't been enabled
    by the kernel itself and the power-off will trigger some faults.
    This patch enable the clocks to have a coherent state for an eventual
    poweroff and switches to the pm_domain_always_on_gov governor.

I could set always-on governor only if the domain was already enabled,
what do you think ?

And seems I'm also missing the "This patch enable the clocks".

> 
>> +	return 0;
>> +}
>> +
>> +static int meson_ee_pwrc_probe(struct platform_device *pdev)
>> +{
>> +	const struct meson_ee_pwrc_domain_data *match;
>> +	struct regmap *regmap_ao, *regmap_hhi;
>> +	struct meson_ee_pwrc *sm1_pwrc;
> 
> Why the sm1_ prefix throughout this code?  This is now generalized for
> more SoCs, so shouldn't be sm1.  I'm assuming this is just left-over
> from the original version.  IMO, just called it pwrc.

Indeed, it's a leftover.

> 
>> +	int i, ret;
>> +
>> +	match = of_device_get_match_data(&pdev->dev);
>> +	if (!match) {
>> +		dev_err(&pdev->dev, "failed to get match data\n");
>> +		return -ENODEV;
>> +	}
>> +
>> +	sm1_pwrc = devm_kzalloc(&pdev->dev, sizeof(*sm1_pwrc), GFP_KERNEL);
>> +	if (!sm1_pwrc)
>> +		return -ENOMEM;
>> +
>> +	sm1_pwrc->xlate.domains =
>> +		devm_kcalloc(&pdev->dev,
>> +			     match->count,
>> +			     sizeof(*sm1_pwrc->xlate.domains),
>> +			     GFP_KERNEL);
>> +	if (!sm1_pwrc->xlate.domains)
>> +		return -ENOMEM;
>> +
>> +	sm1_pwrc->domains =
>> +		devm_kcalloc(&pdev->dev,
> 
> nit: this line probably doesn't need to be wrapped.

Ok

> 
>> +			     match->count,
>> +			     sizeof(*sm1_pwrc->domains),
>> +			     GFP_KERNEL);
>> +	if (!sm1_pwrc->domains)
>> +		return -ENOMEM;
>> +
>> +	sm1_pwrc->xlate.num_domains = match->count;
>> +
>> +	regmap_hhi = syscon_node_to_regmap(of_get_parent(pdev->dev.of_node));
>> +	if (IS_ERR(regmap_hhi)) {
>> +		dev_err(&pdev->dev, "failed to get HHI regmap\n");
>> +		return PTR_ERR(regmap_hhi);
>> +	}
>> +
>> +	regmap_ao = syscon_regmap_lookup_by_phandle(pdev->dev.of_node,
>> +						    "amlogic,ao-sysctrl");
>> +	if (IS_ERR(regmap_ao)) {
>> +		dev_err(&pdev->dev, "failed to get AO regmap\n");
>> +		return PTR_ERR(regmap_ao);
>> +	}
>> +
>> +	sm1_pwrc->regmap_ao = regmap_ao;
>> +	sm1_pwrc->regmap_hhi = regmap_hhi;
>> +
>> +	platform_set_drvdata(pdev, sm1_pwrc);
>> +
>> +	for (i = 0 ; i < match->count ; ++i) {
>> +		struct meson_ee_pwrc_domain *dom = &sm1_pwrc->domains[i];
>> +
>> +		memcpy(&dom->desc, &match->domains[i], sizeof(dom->desc));
>> +
>> +		ret = meson_ee_pwrc_init_domain(pdev, sm1_pwrc, dom);
>> +		if (ret)
>> +			return ret;
>> +
>> +		sm1_pwrc->xlate.domains[i] = &dom->base;
>> +	}
>> +
>> +	of_genpd_add_provider_onecell(pdev->dev.of_node, &sm1_pwrc->xlate);
>> +
>> +	return 0;
>> +}
>> +
>> +static struct meson_ee_pwrc_domain_data meson_ee_g12a_pwrc_data = {
>> +	.count = ARRAY_SIZE(g12a_pwrc_domains),
>> +	.domains = g12a_pwrc_domains,
>> +};
>> +
>> +static struct meson_ee_pwrc_domain_data meson_ee_sm1_pwrc_data = {
>> +	.count = ARRAY_SIZE(sm1_pwrc_domains),
>> +	.domains = sm1_pwrc_domains,
>> +};
>> +
>> +static const struct of_device_id meson_ee_pwrc_match_table[] = {
>> +	{
>> +		.compatible = "amlogic,meson-g12a-pwrc",
>> +		.data = &meson_ee_g12a_pwrc_data,
>> +	},
>> +	{
>> +		.compatible = "amlogic,meson-sm1-pwrc",
>> +		.data = &meson_ee_sm1_pwrc_data,
>> +	},
>> +	{ /* sentinel */ }
>> +};
>> +
>> +static struct platform_driver meson_ee_pwrc_driver = {
>> +	.probe	= meson_ee_pwrc_probe,
>> +	.driver = {
>> +		.name		= "meson_ee_pwrc",
>> +		.of_match_table	= meson_ee_pwrc_match_table,
>> +	},
>> +};
>> +builtin_platform_driver(meson_ee_pwrc_driver);
>> -- 
>> 2.22.0

Thanks,
Neil

> 
> Kevin
> 
> [1] https://lore.kernel.org/linux-amlogic/20190809230904.28747-1-khilman@baylibre.com/
> 


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply

* Re: [PATCH v2 2/4] nvmem: meson-efuse: bindings: Add secure-monitor phandle
From: Carlo Caione @ 2019-08-22  8:36 UTC (permalink / raw)
  To: Rob Herring
  Cc: devicetree, narmstrong, khilman, srinivas.kandagatla,
	linux-amlogic, tglx, linux-arm-kernel, jbrunet
In-Reply-To: <20190821181458.GA2886@bogus>

On 21/08/2019 19:14, Rob Herring wrote:
> On Wed, Jul 31, 2019 at 09:23:37AM +0100, Carlo Caione wrote:

> There's no need for 'secure-monitor' anyways. Just do
> 'of_find_compatible_node(NULL, NULL, "amlogic,meson-gxbb-sm")' or search
> for the driver directly. It's not like there's more than one secure
> monitor...

How is hardcoding the secure-monitor directly into the efuse driver 
better than having it referenced in the DT?

Yes, there is one single secure monitor but (even if this is not 
currently the case) several drivers can use it making the secure-monitor 
a resource to be potentially used by several devices.

--
Carlo Caione

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply

* Re: [PATCH 1/9] crypt: Add diskcipher
From: Krzysztof Kozlowski @ 2019-08-22  8:37 UTC (permalink / raw)
  To: boojin.kim
  Cc: Ulf Hansson, Mike Snitzer, dm-devel, Andreas Dilger,
	Alasdair Kergon, Eric Biggers, linux-samsung-soc@vger.kernel.org,
	Herbert Xu, Jaehoon Chung, Kukjin Kim, linux-ext4, Chao Yu,
	linux-block, linux-fscrypt, Jaegeuk Kim, linux-arm-kernel,
	Jens Axboe, Theodore Y. Ts'o, linux-mmc,
	linux-kernel@vger.kernel.org, linux-f2fs-devel, linux-crypto,
	linux-fsdevel, David S. Miller
In-Reply-To: <003d01d557eb$8f6ca210$ae45e630$@samsung.com>

On Wed, 21 Aug 2019 at 08:42, boojin.kim <boojin.kim@samsung.com> wrote:
>
> Diskcipher supports cryptographic operations of inline crypto engines like
> FMP. Inline crypto engine refers to hardware and solutions implemented
> to encrypt data stored in storage device.
>
> When encrypting using the FMP, Additional control is required
> to carry and maintain the crypto information between
> the encryption user(fscrypt, DM-crypt) and FMP driver.
> Diskcipher provides this control.
>
> Diskcipher is a symmetric key cipher in linux crypto API to support FMP.
> FMP are registered with the cihper algorithm that uses diskcipher.
>
> Diskcipher has three major steps.
> The first step is to assign a cipher and set the key.
> The second step is to pass the cipher through the BIO to the storage
> driver.
> The third step is to get the cipher from BIO and request a crypt
> to FMP algorithm.
>
> In the first step, encryption users such as fscrypt or dm-crypt
> allocate/release a diskcipher and set key into the diskcipher.
> Diskcipher provides allocate(), free(), and setkey() that are similar
> to existing ciphers.
>
> In the second step, BIO is used to pass the diskcipher to the storage
> driver.
> The BIO submitters such as ext4, f2fs and DM-crypt set diskcipher to BIO.
> Diskcipher provides the set () API for this.
>
> In the third step, the storage driver extracts the diskcipher from the BIO
> and requests the actual encryption behavior to inline crypto engine driver.
> Diskcipher provides get() and crypt() APIs for this.
>
> Cc: Herbert Xu <herbert@gondor.apana.org.au>
> Cc: David S. Miller <davem@davemloft.net>
> Signed-off-by: Boojin Kim <boojin.kim@samsung.com>
> ---
>  crypto/Kconfig              |   9 ++
>  crypto/Makefile             |   1 +
>  crypto/diskcipher.c         | 349
> ++++++++++++++++++++++++++++++++++++++++++++
>  crypto/testmgr.c            | 157 ++++++++++++++++++++
>  include/crypto/diskcipher.h | 245 +++++++++++++++++++++++++++++++
>  include/linux/crypto.h      |   1 +
>  6 files changed, 762 insertions(+)
>  create mode 100644 crypto/diskcipher.c
>  create mode 100644 include/crypto/diskcipher.h
>
> diff --git a/crypto/Kconfig b/crypto/Kconfig
> index 455a335..382d43a 100644
> --- a/crypto/Kconfig
> +++ b/crypto/Kconfig
> @@ -1636,6 +1636,15 @@ config CRYPTO_TWOFISH_AVX_X86_64
>           See also:
>           <http://www.schneier.com/twofish.html>
>
> +config CRYPTO_DISKCIPHER
> +       bool "Diskcipher support"
> +       default n
> +       help
> +         Disk cipher algorithm
> +
> +         This cipher supports the crypt operation of the block host device
> +         that has inline crypto engine.
> +
>  comment "Compression"
>
>  config CRYPTO_DEFLATE
> diff --git a/crypto/Makefile b/crypto/Makefile
> index 0d2cdd5..71df76a 100644
> --- a/crypto/Makefile
> +++ b/crypto/Makefile
> @@ -165,6 +165,7 @@ obj-$(CONFIG_CRYPTO_USER_API_AEAD) += algif_aead.o
>  obj-$(CONFIG_CRYPTO_ZSTD) += zstd.o
>  obj-$(CONFIG_CRYPTO_OFB) += ofb.o
>  obj-$(CONFIG_CRYPTO_ECC) += ecc.o
> +obj-$(CONFIG_CRYPTO_DISKCIPHER) += diskcipher.o
>
>  ecdh_generic-y += ecdh.o
>  ecdh_generic-y += ecdh_helper.o
> diff --git a/crypto/diskcipher.c b/crypto/diskcipher.c
> new file mode 100644
> index 0000000..ffe95a5
> --- /dev/null
> +++ b/crypto/diskcipher.c
> @@ -0,0 +1,349 @@
> +// SPDX-License-Identifier: GPL-2.0-or-later
> +/*
> + * Copyright (C) 2017 Samsung Electronics Co., Ltd.
> + *
> + * 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.
> + */
> +
> +#include <linux/kernel.h>
> +#include <linux/blkdev.h>
> +#include <linux/errno.h>
> +#include <linux/module.h>
> +#include <linux/seq_file.h>
> +#include <linux/string.h>
> +#include <linux/crypto.h>
> +#include <crypto/algapi.h>
> +#include <crypto/diskcipher.h>
> +#include <linux/delay.h>
> +#include <linux/mm_types.h>
> +#include <linux/fs.h>
> +#include <linux/fscrypt.h>
> +
> +#include "internal.h"
> +
> +static int crypto_diskcipher_check(struct bio *bio)
> +{
> +       struct crypto_diskcipher *ci = NULL;
> +       struct inode *inode = NULL;
> +       struct page *page = NULL;
> +
> +       if (!bio) {
> +               pr_err("%s: doesn't exist bio\n", __func__);
> +               return 0;
> +       }
> +
> +       /* enc without fscrypt */
> +       ci = bio->bi_aux_private;
> +       if (!ci->inode)
> +               return 0;
> +       if (ci->algo == 0)
> +               return 0;
> +
> +       page = bio->bi_io_vec[0].bv_page;
> +       if (!page || PageAnon(page) || !page->mapping ||
> !page->mapping->host)

Your patch looks corrupted - wrapped by mailer. The easiest way
usually is to use git format-patch and git send-email - then you do
not have to worry about formatting etc.

Best regards,
Krzysztof

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply

* Re: [PATCH 1/4] misc: xilinx_sdfec: Fix a couple small information leaks
From: Michal Simek @ 2019-08-22  8:49 UTC (permalink / raw)
  To: Dan Carpenter, Michal Simek
  Cc: Arnd Bergmann, Greg Kroah-Hartman, Dragan Cvetic, kernel-janitors,
	linux-kernel, Derek Kiernan, linux-arm-kernel
In-Reply-To: <20190822082831.GH3964@kadam>

On 22. 08. 19 10:28, Dan Carpenter wrote:
> On Thu, Aug 22, 2019 at 10:14:12AM +0200, Michal Simek wrote:
>> Hi Dan,
>>
>> On 21. 08. 19 9:06, Dan Carpenter wrote:
>>> These structs have holes in them so we end up disclosing a few bytes of
>>> uninitialized stack data.
>>>
>>> drivers/misc/xilinx_sdfec.c:305 xsdfec_get_status() warn: check that 'status' doesn't leak information (struct has a hole after 'activity')
>>> drivers/misc/xilinx_sdfec.c:449 xsdfec_get_turbo() warn: check that 'turbo_params' doesn't leak information (struct has a hole after 'scale')
>>
>> Who is generating these warnings? Is this any new GCC or different tool?
>> I see that 3byte padding but never seen these warnings.
> 
> This is a Smatch check.

ok. It looks like I need to update it to latest version. My version is
not showing these.

Anyway thanks for patches,
Michal

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply

* Re: [PATCH 2/2] pwm: pwm-mediatek: Add MT8516 SoC support
From: Matthias Brugger @ 2019-08-22  8:52 UTC (permalink / raw)
  To: Fabien Parent, thierry.reding, robh+dt
  Cc: mark.rutland, linux-pwm, devicetree, linux-kernel, linux-mediatek,
	linux-arm-kernel
In-Reply-To: <20190805125848.15751-2-fparent@baylibre.com>



On 05/08/2019 14:58, Fabien Parent wrote:
> Add the compatible and the platform data to support PWM on the MT8516
> SoC.
> 
> Signed-off-by: Fabien Parent <fparent@baylibre.com>

Reviewed-by: Matthias Brugger <matthias.bgg@gmail.com>

> ---
>  drivers/pwm/pwm-mediatek.c | 7 +++++++
>  1 file changed, 7 insertions(+)
> 
> diff --git a/drivers/pwm/pwm-mediatek.c b/drivers/pwm/pwm-mediatek.c
> index eb6674ce995f..6697e30811e7 100644
> --- a/drivers/pwm/pwm-mediatek.c
> +++ b/drivers/pwm/pwm-mediatek.c
> @@ -302,11 +302,18 @@ static const struct mtk_pwm_platform_data mt7628_pwm_data = {
>  	.has_clks = false,
>  };
>  
> +static const struct mtk_pwm_platform_data mt8516_pwm_data = {
> +	.num_pwms = 5,
> +	.pwm45_fixup = false,
> +	.has_clks = true,
> +};
> +
>  static const struct of_device_id mtk_pwm_of_match[] = {
>  	{ .compatible = "mediatek,mt2712-pwm", .data = &mt2712_pwm_data },
>  	{ .compatible = "mediatek,mt7622-pwm", .data = &mt7622_pwm_data },
>  	{ .compatible = "mediatek,mt7623-pwm", .data = &mt7623_pwm_data },
>  	{ .compatible = "mediatek,mt7628-pwm", .data = &mt7628_pwm_data },
> +	{ .compatible = "mediatek,mt8516-pwm", .data = &mt8516_pwm_data },
>  	{ },
>  };
>  MODULE_DEVICE_TABLE(of, mtk_pwm_of_match);
> 

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply


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