Linux-ARM-Kernel Archive on lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH] drivers: psci: Allow PSCI node to be disabled
From: Lorenzo Pieralisi @ 2016-10-20 12:58 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20161020123907.GF10234@leverpostej>

On Thu, Oct 20, 2016 at 01:39:07PM +0100, Mark Rutland wrote:
> On Mon, Oct 17, 2016 at 12:46:53PM +0200, Thierry Reding wrote:
> > From: Thierry Reding <treding@nvidia.com>
> > 
> > Allow disabling PSCI support (mostly for testing purposes) by setting
> > the status property to "disabled". This makes the node behave in much
> > the same way as proper device nodes.
> > 
> > Signed-off-by: Thierry Reding <treding@nvidia.com>
> 
> This looks sensible to me; FWIW:
> 
> Acked-by: Mark Rutland <mark.rutland@arm.com>
> 
> Lorenzo, do we need to batch this up with other PSCI patches, or should
> this go direct to arm-soc?

I am aiming at getting the PSCI checker merged too so that we can send
both patches (and others that may turn up) in one go to arm-soc, I will
handle it.

Thanks !
Lorenzo

> Thanks,
> Mark.
> 
> > ---
> >  drivers/firmware/psci.c | 2 +-
> >  1 file changed, 1 insertion(+), 1 deletion(-)
> > 
> > diff --git a/drivers/firmware/psci.c b/drivers/firmware/psci.c
> > index 8263429e21b8..6c60a5087caf 100644
> > --- a/drivers/firmware/psci.c
> > +++ b/drivers/firmware/psci.c
> > @@ -630,7 +630,7 @@ int __init psci_dt_init(void)
> >  
> >  	np = of_find_matching_node_and_match(NULL, psci_of_match, &matched_np);
> >  
> > -	if (!np)
> > +	if (!np || !of_device_is_available(np))
> >  		return -ENODEV;
> >  
> >  	init_fn = (psci_initcall_t)matched_np->data;
> > -- 
> > 2.10.0
> > 
> 

^ permalink raw reply

* [PATCH v2 8/9] ARM: sunxi: Remove useless allwinner, pull property
From: Linus Walleij @ 2016-10-20 12:57 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <b643d1e525835365a6ae63bcd065cb3650a839d6.1476200742.git-series.maxime.ripard@free-electrons.com>

On Tue, Oct 11, 2016 at 5:46 PM, Maxime Ripard
<maxime.ripard@free-electrons.com> wrote:

> The allwinner,pull property set to NO_PULL was really considered our
> default (and wasn't even changing the default value in the code).
>
> Remove these properties to make it obvious that we do not set anything in
> such a case.
>
> Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>

Reviewed-by: Linus Walleij <linus.walleij@linaro.org>

Please merge this through the ARM SoC tree.

Yours,
Linus Walleij

^ permalink raw reply

* [PATCH v2 7/9] ARM: sunxi: Remove useless allwinner, drive property
From: Linus Walleij @ 2016-10-20 12:55 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <076406072c137a50df41c4acb0c582a688792976.1476200742.git-series.maxime.ripard@free-electrons.com>

On Tue, Oct 11, 2016 at 5:46 PM, Maxime Ripard
<maxime.ripard@free-electrons.com> wrote:

> The allwinner,drive property set to 10mA was really considered as our
> default. Remove all those properties entirely to make that obvious.
>
> Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>

Reviewed-by: Linus Walleij <linus.walleij@linaro.org>

Please merge this through the ARM SoC tree.

Yours,
Linus Walleij

^ permalink raw reply

* [PATCH] kernel: irq: fix build failure
From: Thomas Gleixner @ 2016-10-20 12:55 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <57FBBA0B.9070500@gmail.com>

On Mon, 10 Oct 2016, Sudip Mukherjee wrote:

> On Thursday 06 October 2016 11:06 PM, Sudip Mukherjee wrote:
> > The allmodconfig build of powerpc is failing with the error:
> > ERROR: ".irq_set_parent" [drivers/mfd/tps65217.ko] undefined!
> > 
> > export the symbol to fix the failure.
> 
> Hi Thomas,
> powerpc and arm allmodconfig builds still fails with the same error.
> Build logs of next-20161010 are at:
> arm at https://travis-ci.org/sudipm-mukherjee/parport/jobs/166321467
> powerpc at https://travis-ci.org/sudipm-mukherjee/parport/jobs/166321473

I know. This is under discussion with the driver folks as we are not going
to blindly export stuff just because someone slapped a irq_set_parent()
into the code w/o knowing why.

Thanks,

	tglx

^ permalink raw reply

* [PATCH 2/2] arm64/numa: fix incorrect print of end_pfn
From: Mark Rutland @ 2016-10-20 12:55 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <5808B6D1.809@huawei.com>

On Thu, Oct 20, 2016 at 08:21:37PM +0800, Hanjun Guo wrote:
> On 2016/10/20 18:51, Will Deacon wrote:
> > On Thu, Oct 20, 2016 at 11:52:56AM +0800, Hanjun Guo wrote:
> >> From: Hanjun Guo <hanjun.guo@linaro.org>
> >>
> >> When booting on NUMA system with memory-less node (no
> >> memory dimm on this memory controller), the print
> >> for setup_node_data() is incorrect:
> >>
> >> NUMA: Initmem setup node 2 [mem 0x00000000-0xffffffffffffffff]
> >>
> >> It should be 0, not 0xffffffffffffffff as there is
> >> no memory on that node.
> > Wouldn't it make more sense to print something useful, like "memory-less
> > node"?
> 
> in the log,
> 
> [    0.000000] NUMA: Initmem setup node 0 [mem 0x00000000-0x13fbffffff]
> [    0.000000] NUMA: NODE_DATA [mem 0x13fbffe500-0x13fbffffff]
> [    0.000000] NUMA: Initmem setup node 1 [mem 0x1400000000-0x17fbffffff]
> [    0.000000] NUMA: NODE_DATA [mem 0x17fbfec500-0x17fbfedfff]
> [    0.000000] NUMA: Initmem setup node 2 [mem 0x00000000-0xffffffffffffffff]
> [    0.000000] NUMA: NODE_DATA [mem 0x17fbfeaa00-0x17fbfec4ff]
> [    0.000000] NUMA: NODE_DATA(2) on node 1
> [    0.000000] NUMA: Initmem setup node 3 [mem 0x00000000-0xffffffffffffffff]
> [    0.000000] NUMA: NODE_DATA [mem 0x17fbfe8f00-0x17fbfea9ff]
> [    0.000000] NUMA: NODE_DATA(3) on node 1
> 
> if printing "NUMA: Initmem setup node 2 [mem 0x00000000-0x00000000]",

Seeing "NUMA: Initmem setup node 2 [<memoryless node>]" would be far
more obvious as a memoryless node, and I don't see that this would be
inconsistent.

Thanks,
Mark.

^ permalink raw reply

* [PATCH v2 4/9] pinctrl: sunxi: Deal with configless pins
From: Linus Walleij @ 2016-10-20 12:52 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20161019121614.3crr76qyexhamjiy@lukather>

On Wed, Oct 19, 2016 at 2:16 PM, Maxime Ripard
<maxime.ripard@free-electrons.com> wrote:
> On Tue, Oct 18, 2016 at 03:47:03PM +0800, Chen-Yu Tsai wrote:
>> > @@ -342,6 +365,8 @@ static void sunxi_pctrl_dt_free_map(struct pinctrl_dev *pctldev,
>> >                                     struct pinctrl_map *map,
>> >                                     unsigned num_maps)
>> >  {
>> > +       unsigned long *pinconfig;
>>
>> This looks out of place and context?
>
> Yeah, sorry, it's just a leftover from the previous version. This has
> been removed.

Do you mean you will send a v3 of this series?

OK stopping to apply then.

But I have already applied patches 1, 2 and 3 so just resend the rest :)

Yours,
Linus Walleij

^ permalink raw reply

* [PATCH 2/2] arm64/numa: fix incorrect print of end_pfn
From: Will Deacon @ 2016-10-20 12:52 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <5808B6D1.809@huawei.com>

On Thu, Oct 20, 2016 at 08:21:37PM +0800, Hanjun Guo wrote:
> On 2016/10/20 18:51, Will Deacon wrote:
> > On Thu, Oct 20, 2016 at 11:52:56AM +0800, Hanjun Guo wrote:
> >> From: Hanjun Guo <hanjun.guo@linaro.org>
> >>
> >> When booting on NUMA system with memory-less node (no
> >> memory dimm on this memory controller), the print
> >> for setup_node_data() is incorrect:
> >>
> >> NUMA: Initmem setup node 2 [mem 0x00000000-0xffffffffffffffff]
> >>
> >> It should be 0, not 0xffffffffffffffff as there is
> >> no memory on that node.
> > Wouldn't it make more sense to print something useful, like "memory-less
> > node"?
> 
> in the log,
> 
> [    0.000000] NUMA: Initmem setup node 0 [mem 0x00000000-0x13fbffffff]
> [    0.000000] NUMA: NODE_DATA [mem 0x13fbffe500-0x13fbffffff]
> [    0.000000] NUMA: Initmem setup node 1 [mem 0x1400000000-0x17fbffffff]
> [    0.000000] NUMA: NODE_DATA [mem 0x17fbfec500-0x17fbfedfff]
> [    0.000000] NUMA: Initmem setup node 2 [mem 0x00000000-0xffffffffffffffff]
> [    0.000000] NUMA: NODE_DATA [mem 0x17fbfeaa00-0x17fbfec4ff]
> [    0.000000] NUMA: NODE_DATA(2) on node 1
> [    0.000000] NUMA: Initmem setup node 3 [mem 0x00000000-0xffffffffffffffff]
> [    0.000000] NUMA: NODE_DATA [mem 0x17fbfe8f00-0x17fbfea9ff]
> [    0.000000] NUMA: NODE_DATA(3) on node 1
> 
> if printing "NUMA: Initmem setup node 2 [mem 0x00000000-0x00000000]",
> it will make the log consistent with others, and obvious it's a memory-less
> node as memory range 0x00000000-0x00000000, what do you think?

How is that more obvious than printing the string "memory-less node"?
Is this data parsed by something?

Will

^ permalink raw reply

* [PATCH v2 3/9] pinctrl: sunxi: Handle bias disable
From: Linus Walleij @ 2016-10-20 12:51 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <6f9d91647b9f05a1df5d655a49965b671ba04b71.1476200742.git-series.maxime.ripard@free-electrons.com>

On Tue, Oct 11, 2016 at 5:46 PM, Maxime Ripard
<maxime.ripard@free-electrons.com> wrote:

> So far, putting NO_PULL in allwinner,pull was ignored, behaving like if
> that property was not there at all.
>
> Obviously, this is not the right thing to do, and in that case, we really
> need to just disable the bias.
>
> Acked-by: Chen-Yu Tsai <wens@csie.org>
> Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>

Patch applied.

Yours,
Linus Walleij

^ permalink raw reply

* [PATCH v2 2/9] pinctrl: sunxi: Use macros from bindings header file for DT parsing
From: Linus Walleij @ 2016-10-20 12:50 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <5de3087f625d6d4a4d552d4a85faafac689f5f54.1476200742.git-series.maxime.ripard@free-electrons.com>

On Tue, Oct 11, 2016 at 5:46 PM, Maxime Ripard
<maxime.ripard@free-electrons.com> wrote:

> Since we have some bindings header for our hardcoded flags, let's use them
> when we can.
>
> Acked-by: Chen-Yu Tsai <wens@csie.org>
> Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>

Patch applied.

Yours,
Linus Walleij

^ permalink raw reply

* [PATCH v2 1/9] pinctrl: sunxi: Rework the pin config building code
From: Linus Walleij @ 2016-10-20 12:47 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <709f95f6725453af12bc989ce9039df5aa252ea5.1476200742.git-series.maxime.ripard@free-electrons.com>

On Tue, Oct 11, 2016 at 5:45 PM, Maxime Ripard
<maxime.ripard@free-electrons.com> wrote:

> In order to support more easily the generic pinctrl properties, rework the
> pinctrl maps configuration and split it into several sub-functions.
>
> One of the side-effects from that rework is that we only parse the pin
> configuration once, since it's going to be common to every pin, instead of
> having to parsing once for each pin.
>
> Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>

Patch applied.

Yours,
Linus Walleij

^ permalink raw reply

* [PATCHv4 03/15] dt-bindings: clock: add omap4 hwmod clock IDs
From: Tony Lindgren @ 2016-10-20 12:47 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1476805568-19264-4-git-send-email-t-kristo@ti.com>

* Tero Kristo <t-kristo@ti.com> [161018 08:47]:
> Add IDs for omap4 hwmod clocks. These are basically register offsets
> from the beginning of the clockdomain address space.

Looks like you have a wrong subject for this patch?

Tony

^ permalink raw reply

* [PATCH] drivers: psci: Allow PSCI node to be disabled
From: Mark Rutland @ 2016-10-20 12:39 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20161017104653.18783-1-thierry.reding@gmail.com>

On Mon, Oct 17, 2016 at 12:46:53PM +0200, Thierry Reding wrote:
> From: Thierry Reding <treding@nvidia.com>
> 
> Allow disabling PSCI support (mostly for testing purposes) by setting
> the status property to "disabled". This makes the node behave in much
> the same way as proper device nodes.
> 
> Signed-off-by: Thierry Reding <treding@nvidia.com>

This looks sensible to me; FWIW:

Acked-by: Mark Rutland <mark.rutland@arm.com>

Lorenzo, do we need to batch this up with other PSCI patches, or should
this go direct to arm-soc?

Thanks,
Mark.

> ---
>  drivers/firmware/psci.c | 2 +-
>  1 file changed, 1 insertion(+), 1 deletion(-)
> 
> diff --git a/drivers/firmware/psci.c b/drivers/firmware/psci.c
> index 8263429e21b8..6c60a5087caf 100644
> --- a/drivers/firmware/psci.c
> +++ b/drivers/firmware/psci.c
> @@ -630,7 +630,7 @@ int __init psci_dt_init(void)
>  
>  	np = of_find_matching_node_and_match(NULL, psci_of_match, &matched_np);
>  
> -	if (!np)
> +	if (!np || !of_device_is_available(np))
>  		return -ENODEV;
>  
>  	init_fn = (psci_initcall_t)matched_np->data;
> -- 
> 2.10.0
> 

^ permalink raw reply

* [PATCH v3 2/3] drm: zte: add initial vou drm driver
From: Gustavo Padovan @ 2016-10-20 12:29 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1476948625-8521-3-git-send-email-shawn.guo@linaro.org>

2016-10-20 Shawn Guo <shawn.guo@linaro.org>:

> It adds the initial ZTE VOU display controller DRM driver.  There are
> still some features to be added, like overlay plane, scaling, and more
> output devices support.  But it's already useful with dual CRTCs and
> HDMI monitor working.
> 
> Signed-off-by: Shawn Guo <shawn.guo@linaro.org>
> ---
>  drivers/gpu/drm/Kconfig          |   2 +
>  drivers/gpu/drm/Makefile         |   1 +
>  drivers/gpu/drm/zte/Kconfig      |   8 +
>  drivers/gpu/drm/zte/Makefile     |   7 +
>  drivers/gpu/drm/zte/zx_drm_drv.c | 267 +++++++++++++
>  drivers/gpu/drm/zte/zx_drm_drv.h |  36 ++
>  drivers/gpu/drm/zte/zx_hdmi.c    | 678 +++++++++++++++++++++++++++++++++
>  drivers/gpu/drm/zte/zx_plane.c   | 375 ++++++++++++++++++
>  drivers/gpu/drm/zte/zx_plane.h   |  26 ++
>  drivers/gpu/drm/zte/zx_vou.c     | 799 +++++++++++++++++++++++++++++++++++++++
>  drivers/gpu/drm/zte/zx_vou.h     |  46 +++
>  11 files changed, 2245 insertions(+)
>  create mode 100644 drivers/gpu/drm/zte/Kconfig
>  create mode 100644 drivers/gpu/drm/zte/Makefile
>  create mode 100644 drivers/gpu/drm/zte/zx_drm_drv.c
>  create mode 100644 drivers/gpu/drm/zte/zx_drm_drv.h
>  create mode 100644 drivers/gpu/drm/zte/zx_hdmi.c
>  create mode 100644 drivers/gpu/drm/zte/zx_plane.c
>  create mode 100644 drivers/gpu/drm/zte/zx_plane.h
>  create mode 100644 drivers/gpu/drm/zte/zx_vou.c
>  create mode 100644 drivers/gpu/drm/zte/zx_vou.h
> 
> diff --git a/drivers/gpu/drm/Kconfig b/drivers/gpu/drm/Kconfig
> index 483059a22b1b..a91f8cecbe0f 100644
> --- a/drivers/gpu/drm/Kconfig
> +++ b/drivers/gpu/drm/Kconfig
> @@ -223,6 +223,8 @@ source "drivers/gpu/drm/hisilicon/Kconfig"
>  
>  source "drivers/gpu/drm/mediatek/Kconfig"
>  
> +source "drivers/gpu/drm/zte/Kconfig"
> +
>  # Keep legacy drivers last
>  
>  menuconfig DRM_LEGACY
> diff --git a/drivers/gpu/drm/Makefile b/drivers/gpu/drm/Makefile
> index 25c720454017..f3251750c92b 100644
> --- a/drivers/gpu/drm/Makefile
> +++ b/drivers/gpu/drm/Makefile
> @@ -86,3 +86,4 @@ obj-$(CONFIG_DRM_FSL_DCU) += fsl-dcu/
>  obj-$(CONFIG_DRM_ETNAVIV) += etnaviv/
>  obj-$(CONFIG_DRM_ARCPGU)+= arc/
>  obj-y			+= hisilicon/
> +obj-$(CONFIG_DRM_ZTE)	+= zte/
> diff --git a/drivers/gpu/drm/zte/Kconfig b/drivers/gpu/drm/zte/Kconfig
> new file mode 100644
> index 000000000000..4065b2840f1c
> --- /dev/null
> +++ b/drivers/gpu/drm/zte/Kconfig
> @@ -0,0 +1,8 @@
> +config DRM_ZTE
> +	tristate "DRM Support for ZTE SoCs"
> +	depends on DRM && ARCH_ZX
> +	select DRM_KMS_CMA_HELPER
> +	select DRM_KMS_FB_HELPER
> +	select DRM_KMS_HELPER
> +	help
> +	  Choose this option to enable DRM on ZTE ZX SoCs.
> diff --git a/drivers/gpu/drm/zte/Makefile b/drivers/gpu/drm/zte/Makefile
> new file mode 100644
> index 000000000000..699180bfd57c
> --- /dev/null
> +++ b/drivers/gpu/drm/zte/Makefile
> @@ -0,0 +1,7 @@
> +zxdrm-y := \
> +	zx_drm_drv.o \
> +	zx_hdmi.o \
> +	zx_plane.o \
> +	zx_vou.o
> +
> +obj-$(CONFIG_DRM_ZTE) += zxdrm.o
> diff --git a/drivers/gpu/drm/zte/zx_drm_drv.c b/drivers/gpu/drm/zte/zx_drm_drv.c
> new file mode 100644
> index 000000000000..2476a9b92cea
> --- /dev/null
> +++ b/drivers/gpu/drm/zte/zx_drm_drv.c
> @@ -0,0 +1,267 @@
> +/*
> + * Copyright 2016 Linaro Ltd.
> + * Copyright 2016 ZTE Corporation.
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License version 2 as
> + * published by the Free Software Foundation.
> + *
> + */
> +
> +#include <linux/clk.h>
> +#include <linux/component.h>
> +#include <linux/list.h>
> +#include <linux/module.h>
> +#include <linux/of_graph.h>
> +#include <linux/of_platform.h>
> +#include <linux/spinlock.h>
> +
> +#include <drm/drm_atomic_helper.h>
> +#include <drm/drm_crtc.h>
> +#include <drm/drm_crtc_helper.h>
> +#include <drm/drm_fb_cma_helper.h>
> +#include <drm/drm_fb_helper.h>
> +#include <drm/drm_gem_cma_helper.h>
> +#include <drm/drm_of.h>
> +#include <drm/drmP.h>
> +
> +#include "zx_drm_drv.h"
> +#include "zx_vou.h"
> +
> +struct zx_drm_private {
> +	struct drm_fbdev_cma *fbdev;
> +};
> +
> +static void zx_drm_fb_output_poll_changed(struct drm_device *drm)
> +{
> +	struct zx_drm_private *priv = drm->dev_private;
> +
> +	drm_fbdev_cma_hotplug_event(priv->fbdev);
> +}
> +
> +static const struct drm_mode_config_funcs zx_drm_mode_config_funcs = {
> +	.fb_create = drm_fb_cma_create,
> +	.output_poll_changed = zx_drm_fb_output_poll_changed,
> +	.atomic_check = drm_atomic_helper_check,
> +	.atomic_commit = drm_atomic_helper_commit,
> +};
> +
> +static void zx_drm_lastclose(struct drm_device *drm)
> +{
> +	struct zx_drm_private *priv = drm->dev_private;
> +
> +	drm_fbdev_cma_restore_mode(priv->fbdev);
> +}
> +
> +static const struct file_operations zx_drm_fops = {
> +	.owner = THIS_MODULE,
> +	.open = drm_open,
> +	.release = drm_release,
> +	.unlocked_ioctl = drm_ioctl,
> +#ifdef CONFIG_COMPAT
> +	.compat_ioctl = drm_compat_ioctl,
> +#endif
> +	.poll = drm_poll,
> +	.read = drm_read,
> +	.llseek = noop_llseek,
> +	.mmap = drm_gem_cma_mmap,
> +};
> +
> +static struct drm_driver zx_drm_driver = {
> +	.driver_features = DRIVER_GEM | DRIVER_MODESET | DRIVER_PRIME |
> +			   DRIVER_ATOMIC,
> +	.lastclose = zx_drm_lastclose,
> +	.get_vblank_counter = drm_vblank_no_hw_counter,
> +	.enable_vblank = zx_vou_enable_vblank,
> +	.disable_vblank = zx_vou_disable_vblank,
> +	.gem_free_object = drm_gem_cma_free_object,
> +	.gem_vm_ops = &drm_gem_cma_vm_ops,
> +	.dumb_create = drm_gem_cma_dumb_create,
> +	.dumb_map_offset = drm_gem_cma_dumb_map_offset,
> +	.dumb_destroy = drm_gem_dumb_destroy,
> +	.prime_handle_to_fd = drm_gem_prime_handle_to_fd,
> +	.prime_fd_to_handle = drm_gem_prime_fd_to_handle,
> +	.gem_prime_export = drm_gem_prime_export,
> +	.gem_prime_import = drm_gem_prime_import,
> +	.gem_prime_get_sg_table = drm_gem_cma_prime_get_sg_table,
> +	.gem_prime_import_sg_table = drm_gem_cma_prime_import_sg_table,
> +	.gem_prime_vmap = drm_gem_cma_prime_vmap,
> +	.gem_prime_vunmap = drm_gem_cma_prime_vunmap,
> +	.gem_prime_mmap = drm_gem_cma_prime_mmap,
> +	.fops = &zx_drm_fops,
> +	.name = "zx-vou",
> +	.desc = "ZTE VOU Controller DRM",
> +	.date = "20160811",
> +	.major = 1,
> +	.minor = 0,
> +};
> +
> +static int zx_drm_bind(struct device *dev)
> +{
> +	struct drm_device *drm;
> +	struct zx_drm_private *priv;
> +	int ret;
> +
> +	priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
> +	if (!priv)
> +		return -ENOMEM;
> +
> +	drm = drm_dev_alloc(&zx_drm_driver, dev);
> +	if (!drm)
> +		return -ENOMEM;
> +
> +	drm->dev_private = priv;
> +	dev_set_drvdata(dev, drm);
> +
> +	drm_mode_config_init(drm);
> +	drm->mode_config.min_width = 16;
> +	drm->mode_config.min_height = 16;
> +	drm->mode_config.max_width = 4096;
> +	drm->mode_config.max_height = 4096;
> +	drm->mode_config.funcs = &zx_drm_mode_config_funcs;
> +
> +	ret = component_bind_all(dev, drm);
> +	if (ret) {
> +		dev_err(dev, "failed to bind all components: %d\n", ret);
> +		goto out_unregister;
> +	}
> +
> +	ret = drm_vblank_init(drm, drm->mode_config.num_crtc);
> +	if (ret < 0) {
> +		dev_err(dev, "failed to init vblank: %d\n", ret);
> +		goto out_unbind;
> +	}
> +
> +	/*
> +	 * We will manage irq handler on our own.  In this case, irq_enabled
> +	 * need to be true for using vblank core support.
> +	 */
> +	drm->irq_enabled = true;
> +
> +	drm_mode_config_reset(drm);
> +	drm_kms_helper_poll_init(drm);
> +
> +	priv->fbdev = drm_fbdev_cma_init(drm, 32, drm->mode_config.num_crtc,
> +					 drm->mode_config.num_connector);
> +	if (IS_ERR(priv->fbdev)) {
> +		ret = PTR_ERR(priv->fbdev);
> +		dev_err(dev, "failed to init cma fbdev: %d\n", ret);
> +		priv->fbdev = NULL;
> +		goto out_poll_fini;
> +	}
> +
> +	ret = drm_dev_register(drm, 0);
> +	if (ret)
> +		goto out_fbdev_fini;
> +
> +	return 0;
> +
> +out_fbdev_fini:
> +	if (priv->fbdev) {
> +		drm_fbdev_cma_fini(priv->fbdev);
> +		priv->fbdev = NULL;
> +	}
> +out_poll_fini:
> +	drm_kms_helper_poll_fini(drm);
> +	drm_mode_config_cleanup(drm);
> +	drm_vblank_cleanup(drm);
> +out_unbind:
> +	component_unbind_all(dev, drm);
> +out_unregister:
> +	dev_set_drvdata(dev, NULL);
> +	drm->dev_private = NULL;
> +	drm_dev_unref(drm);
> +	return ret;
> +}
> +
> +static void zx_drm_unbind(struct device *dev)
> +{
> +	struct drm_device *drm = dev_get_drvdata(dev);
> +	struct zx_drm_private *priv = drm->dev_private;
> +
> +	drm_dev_unregister(drm);
> +	if (priv->fbdev) {
> +		drm_fbdev_cma_fini(priv->fbdev);
> +		priv->fbdev = NULL;
> +	}
> +	drm_kms_helper_poll_fini(drm);
> +	drm_mode_config_cleanup(drm);
> +	drm_vblank_cleanup(drm);
> +	component_unbind_all(dev, drm);
> +	dev_set_drvdata(dev, NULL);
> +	drm->dev_private = NULL;
> +	drm_dev_unref(drm);
> +}
> +
> +static const struct component_master_ops zx_drm_master_ops = {
> +	.bind = zx_drm_bind,
> +	.unbind = zx_drm_unbind,
> +};
> +
> +static int compare_of(struct device *dev, void *data)
> +{
> +	return dev->of_node == data;
> +}
> +
> +static int zx_drm_probe(struct platform_device *pdev)
> +{
> +	struct device *dev = &pdev->dev;
> +	struct device_node *parent = dev->of_node;
> +	struct device_node *child;
> +	struct component_match *match = NULL;
> +	int ret;
> +
> +	ret = of_platform_populate(parent, NULL, NULL, dev);
> +	if (ret)
> +		return ret;
> +
> +	for_each_available_child_of_node(parent, child) {
> +		component_match_add(dev, &match, compare_of, child);
> +		of_node_put(child);
> +	}
> +
> +	return component_master_add_with_match(dev, &zx_drm_master_ops, match);
> +}
> +
> +static int zx_drm_remove(struct platform_device *pdev)
> +{
> +	component_master_del(&pdev->dev, &zx_drm_master_ops);
> +	return 0;
> +}
> +
> +static const struct of_device_id zx_drm_of_match[] = {
> +	{ .compatible = "zte,zx296718-vou", },
> +	{ /* end */ },
> +};
> +MODULE_DEVICE_TABLE(of, zx_drm_of_match);
> +
> +static struct platform_driver zx_drm_platform_driver = {
> +	.probe = zx_drm_probe,
> +	.remove = zx_drm_remove,
> +	.driver	= {
> +		.name = "zx-drm",
> +		.of_match_table	= zx_drm_of_match,
> +	},
> +};
> +
> +static struct platform_driver *drivers[] = {
> +	&zx_crtc_driver,
> +	&zx_hdmi_driver,
> +	&zx_drm_platform_driver,
> +};
> +
> +static int zx_drm_init(void)
> +{
> +	return platform_register_drivers(drivers, ARRAY_SIZE(drivers));
> +}
> +module_init(zx_drm_init);
> +
> +static void zx_drm_exit(void)
> +{
> +	platform_unregister_drivers(drivers, ARRAY_SIZE(drivers));
> +}
> +module_exit(zx_drm_exit);
> +
> +MODULE_AUTHOR("Shawn Guo <shawn.guo@linaro.org>");
> +MODULE_DESCRIPTION("ZTE ZX VOU DRM driver");
> +MODULE_LICENSE("GPL v2");
> diff --git a/drivers/gpu/drm/zte/zx_drm_drv.h b/drivers/gpu/drm/zte/zx_drm_drv.h
> new file mode 100644
> index 000000000000..e65cd18a6cba
> --- /dev/null
> +++ b/drivers/gpu/drm/zte/zx_drm_drv.h
> @@ -0,0 +1,36 @@
> +/*
> + * Copyright 2016 Linaro Ltd.
> + * Copyright 2016 ZTE Corporation.
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License version 2 as
> + * published by the Free Software Foundation.
> + *
> + */
> +
> +#ifndef __ZX_DRM_DRV_H__
> +#define __ZX_DRM_DRV_H__
> +
> +extern struct platform_driver zx_crtc_driver;
> +extern struct platform_driver zx_hdmi_driver;
> +
> +static inline u32 zx_readl(void __iomem *reg)
> +{
> +	return readl_relaxed(reg);
> +}
> +
> +static inline void zx_writel(void __iomem *reg, u32 val)
> +{
> +	writel_relaxed(val, reg);
> +}
> +
> +static inline void zx_writel_mask(void __iomem *reg, u32 mask, u32 val)
> +{
> +	u32 tmp;
> +
> +	tmp = zx_readl(reg);
> +	tmp = (tmp & ~mask) | (val & mask);
> +	zx_writel(reg, tmp);
> +}
> +
> +#endif /* __ZX_DRM_DRV_H__ */
> diff --git a/drivers/gpu/drm/zte/zx_hdmi.c b/drivers/gpu/drm/zte/zx_hdmi.c
> new file mode 100644
> index 000000000000..81e1c3716ed8
> --- /dev/null
> +++ b/drivers/gpu/drm/zte/zx_hdmi.c
> @@ -0,0 +1,678 @@
> +/*
> + * Copyright 2016 Linaro Ltd.
> + * Copyright 2016 ZTE Corporation.
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License version 2 as
> + * published by the Free Software Foundation.
> + *
> + */
> +
> +#include <linux/clk.h>
> +#include <linux/component.h>
> +#include <linux/delay.h>
> +#include <linux/err.h>
> +#include <linux/hdmi.h>
> +#include <linux/irq.h>
> +#include <linux/mfd/syscon.h>
> +#include <linux/module.h>
> +#include <linux/mutex.h>
> +#include <linux/of_device.h>
> +
> +#include <drm/drm_atomic_helper.h>
> +#include <drm/drm_crtc_helper.h>
> +#include <drm/drm_edid.h>
> +#include <drm/drm_of.h>
> +#include <drm/drmP.h>
> +
> +#include "zx_vou.h"
> +
> +#define FUNC_SEL			0x000b
> +#define FUNC_HDMI_EN			BIT(0)
> +#define CLKPWD				0x000d
> +#define CLKPWD_PDIDCK			BIT(2)
> +#define PWD_SRST			0x0010
> +#define P2T_CTRL			0x0066
> +#define P2T_DC_PKT_EN			BIT(7)
> +#define L1_INTR_STAT			0x007e
> +#define L1_INTR_STAT_INTR1		BIT(0)
> +#define INTR1_STAT			0x008f
> +#define INTR1_MASK			0x0095
> +#define INTR1_MONITOR_DETECT		(BIT(5) | BIT(6))
> +#define ZX_DDC_ADDR			0x00ed
> +#define ZX_DDC_SEGM			0x00ee
> +#define ZX_DDC_OFFSET			0x00ef
> +#define ZX_DDC_DIN_CNT1			0x00f0
> +#define ZX_DDC_DIN_CNT2			0x00f1
> +#define ZX_DDC_CMD			0x00f3
> +#define DDC_CMD_MASK			0xf
> +#define DDC_CMD_CLEAR_FIFO		0x9
> +#define DDC_CMD_SEQUENTIAL_READ		0x2
> +#define ZX_DDC_DATA			0x00f4
> +#define ZX_DDC_DOUT_CNT			0x00f5
> +#define DDC_DOUT_CNT_MASK		0x1f
> +#define TEST_TXCTRL			0x00f7
> +#define TEST_TXCTRL_HDMI_MODE		BIT(1)
> +#define HDMICTL4			0x0235
> +#define TPI_HPD_RSEN			0x063b
> +#define TPI_HPD_CONNECTION		(BIT(1) | BIT(2))
> +#define TPI_INFO_FSEL			0x06bf
> +#define FSEL_AVI			0
> +#define FSEL_GBD			1
> +#define FSEL_AUDIO			2
> +#define FSEL_SPD			3
> +#define FSEL_MPEG			4
> +#define FSEL_VSIF			5
> +#define TPI_INFO_B0			0x06c0
> +#define TPI_INFO_EN			0x06df
> +#define TPI_INFO_TRANS_EN		BIT(7)
> +#define TPI_INFO_TRANS_RPT		BIT(6)
> +#define TPI_DDC_MASTER_EN		0x06f8
> +#define HW_DDC_MASTER			BIT(7)
> +
> +#define ZX_HDMI_INFOFRAME_SIZE		31
> +
> +#define DDC_SEGMENT_ADDR		0x30
> +
> +struct zx_hdmi_i2c {
> +	struct i2c_adapter adap;
> +	struct mutex lock;
> +};
> +
> +struct zx_hdmi {
> +	struct drm_connector connector;
> +	struct drm_encoder encoder;
> +	struct zx_hdmi_i2c *ddc;
> +	struct device *dev;
> +	struct drm_device *drm;
> +	void __iomem *mmio;
> +	struct clk *cec_clk;
> +	struct clk *osc_clk;
> +	struct clk *xclk;
> +	bool sink_is_hdmi;
> +	bool sink_has_audio;
> +	const struct vou_inf *inf;
> +};
> +
> +#define to_zx_hdmi(x) container_of(x, struct zx_hdmi, x)
> +
> +static const struct vou_inf vou_inf_hdmi = {
> +	.id = VOU_HDMI,
> +	.data_sel = VOU_YUV444,
> +	.clocks_en_bits = BIT(24) | BIT(18) | BIT(6),
> +	.clocks_sel_bits = BIT(13) | BIT(2),
> +};
> +
> +static inline u8 hdmi_readb(struct zx_hdmi *hdmi, u16 offset)
> +{
> +	return readl_relaxed(hdmi->mmio + offset * 4);
> +}
> +
> +static inline void hdmi_writeb(struct zx_hdmi *hdmi, u16 offset, u8 val)
> +{
> +	writel_relaxed(val, hdmi->mmio + offset * 4);
> +}
> +
> +static inline void hdmi_writeb_mask(struct zx_hdmi *hdmi, u16 offset,
> +				    u8 mask, u8 val)
> +{
> +	u8 tmp;
> +
> +	tmp = hdmi_readb(hdmi, offset);
> +	tmp = (tmp & ~mask) | (val & mask);
> +	hdmi_writeb(hdmi, offset, tmp);
> +}
> +
> +static int zx_hdmi_infoframe_trans(struct zx_hdmi *hdmi,
> +				   union hdmi_infoframe *frame, u8 fsel)
> +{
> +	u8 buffer[ZX_HDMI_INFOFRAME_SIZE];
> +	int num;
> +	int i;
> +
> +	hdmi_writeb(hdmi, TPI_INFO_FSEL, fsel);
> +
> +	num = hdmi_infoframe_pack(frame, buffer, ZX_HDMI_INFOFRAME_SIZE);
> +	if (num < 0) {
> +		dev_err(hdmi->dev, "failed to pack infoframe: %d\n", num);
> +		return num;
> +	}
> +
> +	for (i = 0; i < num; i++)
> +		hdmi_writeb(hdmi, TPI_INFO_B0 + i, buffer[i]);
> +
> +	hdmi_writeb_mask(hdmi, TPI_INFO_EN, TPI_INFO_TRANS_RPT,
> +			 TPI_INFO_TRANS_RPT);
> +	hdmi_writeb_mask(hdmi, TPI_INFO_EN, TPI_INFO_TRANS_EN,
> +			 TPI_INFO_TRANS_EN);
> +
> +	return num;
> +}
> +
> +static int zx_hdmi_config_video_vsi(struct zx_hdmi *hdmi,
> +				    struct drm_display_mode *mode)
> +{
> +	union hdmi_infoframe frame;
> +	int ret;
> +
> +	ret = drm_hdmi_vendor_infoframe_from_display_mode(&frame.vendor.hdmi,
> +							  mode);
> +	if (ret) {
> +		dev_err(hdmi->dev, "failed to get vendor infoframe: %d\n", ret);
> +		return ret;
> +	}
> +
> +	return zx_hdmi_infoframe_trans(hdmi, &frame, FSEL_VSIF);
> +}
> +
> +static int zx_hdmi_config_video_avi(struct zx_hdmi *hdmi,
> +				    struct drm_display_mode *mode)
> +{
> +	union hdmi_infoframe frame;
> +	int ret;
> +
> +	ret = drm_hdmi_avi_infoframe_from_display_mode(&frame.avi, mode);
> +	if (ret) {
> +		dev_err(hdmi->dev, "failed to get avi infoframe: %d\n", ret);
> +		return ret;
> +	}
> +
> +	/* We always use YUV444 for HDMI output. */
> +	frame.avi.colorspace = HDMI_COLORSPACE_YUV444;
> +
> +	return zx_hdmi_infoframe_trans(hdmi, &frame, FSEL_AVI);
> +}
> +
> +static void zx_hdmi_encoder_mode_set(struct drm_encoder *encoder,
> +				     struct drm_display_mode *mode,
> +				     struct drm_display_mode *adj_mode)
> +{
> +	struct zx_hdmi *hdmi = to_zx_hdmi(encoder);
> +
> +	if (hdmi->sink_is_hdmi) {
> +		zx_hdmi_config_video_avi(hdmi, mode);
> +		zx_hdmi_config_video_vsi(hdmi, mode);
> +	}
> +}
> +
> +static void zx_hdmi_encoder_enable(struct drm_encoder *encoder)
> +{
> +	struct zx_hdmi *hdmi = to_zx_hdmi(encoder);
> +
> +	vou_inf_enable(hdmi->inf, encoder->crtc);
> +}
> +
> +static void zx_hdmi_encoder_disable(struct drm_encoder *encoder)
> +{
> +	struct zx_hdmi *hdmi = to_zx_hdmi(encoder);
> +
> +	vou_inf_disable(hdmi->inf, encoder->crtc);
> +}
> +
> +static const struct drm_encoder_helper_funcs zx_hdmi_encoder_helper_funcs = {
> +	.enable	= zx_hdmi_encoder_enable,
> +	.disable = zx_hdmi_encoder_disable,
> +	.mode_set = zx_hdmi_encoder_mode_set,
> +};
> +
> +static const struct drm_encoder_funcs zx_hdmi_encoder_funcs = {
> +	.destroy = drm_encoder_cleanup,
> +};
> +
> +static int zx_hdmi_connector_get_modes(struct drm_connector *connector)
> +{
> +	struct zx_hdmi *hdmi = to_zx_hdmi(connector);
> +	struct edid *edid;
> +	int ret;
> +
> +	edid = drm_get_edid(connector, &hdmi->ddc->adap);
> +	if (!edid)
> +		return 0;
> +
> +	hdmi->sink_is_hdmi = drm_detect_hdmi_monitor(edid);
> +	hdmi->sink_has_audio = drm_detect_monitor_audio(edid);
> +	drm_mode_connector_update_edid_property(connector, edid);
> +	ret = drm_add_edid_modes(connector, edid);
> +	kfree(edid);
> +
> +	return ret;
> +}
> +
> +static enum drm_mode_status
> +zx_hdmi_connector_mode_valid(struct drm_connector *connector,
> +			     struct drm_display_mode *mode)
> +{
> +	return MODE_OK;
> +}
> +
> +static struct drm_connector_helper_funcs zx_hdmi_connector_helper_funcs = {
> +	.get_modes = zx_hdmi_connector_get_modes,
> +	.mode_valid = zx_hdmi_connector_mode_valid,
> +};
> +
> +static enum drm_connector_status
> +zx_hdmi_connector_detect(struct drm_connector *connector, bool force)
> +{
> +	struct zx_hdmi *hdmi = to_zx_hdmi(connector);
> +
> +	return (hdmi_readb(hdmi, TPI_HPD_RSEN) & TPI_HPD_CONNECTION) ?
> +		connector_status_connected : connector_status_disconnected;
> +}
> +
> +static void zx_hdmi_connector_destroy(struct drm_connector *connector)
> +{
> +	drm_connector_unregister(connector);

drm_connector_unregister() is not needed anymore. DRM core will call it
for you.

> +	drm_connector_cleanup(connector);
> +}
> +
> +static const struct drm_connector_funcs zx_hdmi_connector_funcs = {
> +	.dpms = drm_atomic_helper_connector_dpms,
> +	.fill_modes = drm_helper_probe_single_connector_modes,
> +	.detect = zx_hdmi_connector_detect,
> +	.destroy = zx_hdmi_connector_destroy,

Then here you can use drm_connector_cleanup() directly.

> +	.reset = drm_atomic_helper_connector_reset,
> +	.atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
> +	.atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
> +};
> +
> +static int zx_hdmi_register(struct drm_device *drm, struct zx_hdmi *hdmi)
> +{
> +	struct drm_encoder *encoder = &hdmi->encoder;
> +
> +	encoder->possible_crtcs = VOU_CRTC_MASK;
> +
> +	drm_encoder_init(drm, encoder, &zx_hdmi_encoder_funcs,
> +			 DRM_MODE_ENCODER_TMDS, NULL);
> +	drm_encoder_helper_add(encoder, &zx_hdmi_encoder_helper_funcs);
> +
> +	hdmi->connector.polled = DRM_CONNECTOR_POLL_HPD;
> +
> +	drm_connector_init(drm, &hdmi->connector, &zx_hdmi_connector_funcs,
> +			   DRM_MODE_CONNECTOR_HDMIA);
> +	drm_connector_helper_add(&hdmi->connector,
> +				 &zx_hdmi_connector_helper_funcs);
> +
> +	drm_mode_connector_attach_encoder(&hdmi->connector, encoder);
> +
> +	return 0;
> +}
> +
> +static irqreturn_t zx_hdmi_irq_thread(int irq, void *dev_id)
> +{
> +	struct zx_hdmi *hdmi = dev_id;
> +
> +	drm_helper_hpd_irq_event(hdmi->connector.dev);
> +
> +	return IRQ_HANDLED;
> +}
> +
> +static irqreturn_t zx_hdmi_irq_handler(int irq, void *dev_id)
> +{
> +	struct zx_hdmi *hdmi = dev_id;
> +	u8 lstat;
> +
> +	lstat = hdmi_readb(hdmi, L1_INTR_STAT);
> +
> +	/* Monitor detect/HPD interrupt */
> +	if (lstat & L1_INTR_STAT_INTR1) {
> +		u8 stat;
> +
> +		stat = hdmi_readb(hdmi, INTR1_STAT);
> +		hdmi_writeb(hdmi, INTR1_STAT, stat);
> +
> +		if (stat & INTR1_MONITOR_DETECT)
> +			return IRQ_WAKE_THREAD;
> +	}
> +
> +	return IRQ_NONE;
> +}
> +
> +static int zx_hdmi_i2c_read(struct zx_hdmi *hdmi, struct i2c_msg *msg)
> +{
> +	int len = msg->len;
> +	u8 *buf = msg->buf;
> +	int retry = 0;
> +	int ret = 0;
> +
> +	/* Bits [9:8] of bytes */
> +	hdmi_writeb(hdmi, ZX_DDC_DIN_CNT2, (len >> 8) & 0xff);
> +	/* Bits [7:0] of bytes */
> +	hdmi_writeb(hdmi, ZX_DDC_DIN_CNT1, len & 0xff);
> +
> +	/* Clear FIFO */
> +	hdmi_writeb_mask(hdmi, ZX_DDC_CMD, DDC_CMD_MASK, DDC_CMD_CLEAR_FIFO);
> +
> +	/* Kick off the read */
> +	hdmi_writeb_mask(hdmi, ZX_DDC_CMD, DDC_CMD_MASK,
> +			 DDC_CMD_SEQUENTIAL_READ);
> +
> +	while (len > 0) {
> +		int cnt, i;
> +
> +		/* FIFO needs some time to get ready */
> +		usleep_range(500, 1000);
> +
> +		cnt = hdmi_readb(hdmi, ZX_DDC_DOUT_CNT) & DDC_DOUT_CNT_MASK;
> +		if (cnt == 0) {
> +			if (++retry > 5) {
> +				dev_err(hdmi->dev, "DDC FIFO read timed out!");
> +				ret = -ETIMEDOUT;
> +				break;
> +			}
> +			continue;
> +		}
> +
> +		for (i = 0; i < cnt; i++)
> +			*buf++ = hdmi_readb(hdmi, ZX_DDC_DATA);
> +		len -= cnt;
> +	}
> +
> +	return ret;
> +}
> +
> +static int zx_hdmi_i2c_write(struct zx_hdmi *hdmi, struct i2c_msg *msg)
> +{
> +	/*
> +	 * The DDC I2C adapter is only for reading EDID data, so we assume
> +	 * that the write to this adapter must be the EDID data offset.
> +	 */
> +	if ((msg->len != 1) ||
> +	    ((msg->addr != DDC_ADDR) && (msg->addr != DDC_SEGMENT_ADDR)))
> +		return -EINVAL;
> +
> +	if (msg->addr == DDC_SEGMENT_ADDR)
> +		hdmi_writeb(hdmi, ZX_DDC_SEGM, msg->addr << 1);
> +	else if (msg->addr == DDC_ADDR)
> +		hdmi_writeb(hdmi, ZX_DDC_ADDR, msg->addr << 1);
> +
> +	hdmi_writeb(hdmi, ZX_DDC_OFFSET, msg->buf[0]);
> +
> +	return 0;
> +}
> +
> +static int zx_hdmi_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs,
> +			    int num)
> +{
> +	struct zx_hdmi *hdmi = i2c_get_adapdata(adap);
> +	struct zx_hdmi_i2c *ddc = hdmi->ddc;
> +	int i, ret = 0;
> +
> +	mutex_lock(&ddc->lock);
> +
> +	/* Enable DDC master access */
> +	hdmi_writeb_mask(hdmi, TPI_DDC_MASTER_EN, HW_DDC_MASTER, HW_DDC_MASTER);
> +
> +	for (i = 0; i < num; i++) {
> +		dev_dbg(hdmi->dev, "xfer: num: %d/%d, len: %d, flags: %#x\n",
> +			i + 1, num, msgs[i].len, msgs[i].flags);
> +
> +		if (msgs[i].flags & I2C_M_RD)
> +			ret = zx_hdmi_i2c_read(hdmi, &msgs[i]);
> +		else
> +			ret = zx_hdmi_i2c_write(hdmi, &msgs[i]);
> +
> +		if (ret < 0)
> +			break;
> +	}
> +
> +	if (!ret)
> +		ret = num;
> +
> +	/* Disable DDC master access */
> +	hdmi_writeb_mask(hdmi, TPI_DDC_MASTER_EN, HW_DDC_MASTER, 0);
> +
> +	mutex_unlock(&ddc->lock);
> +
> +	return ret;
> +}
> +
> +static u32 zx_hdmi_i2c_func(struct i2c_adapter *adapter)
> +{
> +	return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL;
> +}
> +
> +static const struct i2c_algorithm zx_hdmi_algorithm = {
> +	.master_xfer	= zx_hdmi_i2c_xfer,
> +	.functionality	= zx_hdmi_i2c_func,
> +};
> +
> +static int zx_hdmi_ddc_register(struct zx_hdmi *hdmi)
> +{
> +	struct i2c_adapter *adap;
> +	struct zx_hdmi_i2c *ddc;
> +	int ret;
> +
> +	ddc = devm_kzalloc(hdmi->dev, sizeof(*ddc), GFP_KERNEL);
> +	if (!ddc)
> +		return -ENOMEM;
> +
> +	hdmi->ddc = ddc;
> +	mutex_init(&ddc->lock);
> +
> +	adap = &ddc->adap;
> +	adap->owner = THIS_MODULE;
> +	adap->class = I2C_CLASS_DDC;
> +	adap->dev.parent = hdmi->dev;
> +	adap->algo = &zx_hdmi_algorithm;
> +	snprintf(adap->name, sizeof(adap->name), "zx hdmi i2c");
> +
> +	ret = i2c_add_adapter(adap);
> +	if (ret) {
> +		dev_err(hdmi->dev, "failed to add I2C adapter: %d\n", ret);
> +		return ret;
> +	}
> +
> +	i2c_set_adapdata(adap, hdmi);
> +
> +	return 0;
> +}
> +
> +static void zx_hdmi_phy_start(struct zx_hdmi *hdmi)
> +{
> +	/* Copy from ZTE BSP code */
> +	hdmi_writeb(hdmi, 0x222, 0x0);
> +	hdmi_writeb(hdmi, 0x224, 0x4);
> +	hdmi_writeb(hdmi, 0x909, 0x0);
> +	hdmi_writeb(hdmi, 0x7b0, 0x90);
> +	hdmi_writeb(hdmi, 0x7b1, 0x00);
> +	hdmi_writeb(hdmi, 0x7b2, 0xa7);
> +	hdmi_writeb(hdmi, 0x7b8, 0xaa);
> +	hdmi_writeb(hdmi, 0x7b2, 0xa7);
> +	hdmi_writeb(hdmi, 0x7b3, 0x0f);
> +	hdmi_writeb(hdmi, 0x7b4, 0x0f);
> +	hdmi_writeb(hdmi, 0x7b5, 0x55);
> +	hdmi_writeb(hdmi, 0x7b7, 0x03);
> +	hdmi_writeb(hdmi, 0x7b9, 0x12);
> +	hdmi_writeb(hdmi, 0x7ba, 0x32);
> +	hdmi_writeb(hdmi, 0x7bc, 0x68);
> +	hdmi_writeb(hdmi, 0x7be, 0x40);
> +	hdmi_writeb(hdmi, 0x7bf, 0x84);
> +	hdmi_writeb(hdmi, 0x7c1, 0x0f);
> +	hdmi_writeb(hdmi, 0x7c8, 0x02);
> +	hdmi_writeb(hdmi, 0x7c9, 0x03);
> +	hdmi_writeb(hdmi, 0x7ca, 0x40);
> +	hdmi_writeb(hdmi, 0x7dc, 0x31);
> +	hdmi_writeb(hdmi, 0x7e2, 0x04);
> +	hdmi_writeb(hdmi, 0x7e0, 0x06);
> +	hdmi_writeb(hdmi, 0x7cb, 0x68);
> +	hdmi_writeb(hdmi, 0x7f9, 0x02);
> +	hdmi_writeb(hdmi, 0x7b6, 0x02);
> +	hdmi_writeb(hdmi, 0x7f3, 0x0);
> +}
> +
> +static void zx_hdmi_hw_init(struct zx_hdmi *hdmi)
> +{
> +	/* Software reset */
> +	hdmi_writeb(hdmi, PWD_SRST, 1);
> +
> +	/* Enable pclk */
> +	hdmi_writeb_mask(hdmi, CLKPWD, CLKPWD_PDIDCK, CLKPWD_PDIDCK);
> +
> +	/* Enable HDMI for TX */
> +	hdmi_writeb_mask(hdmi, FUNC_SEL, FUNC_HDMI_EN, FUNC_HDMI_EN);
> +
> +	/* Enable deep color packet */
> +	hdmi_writeb_mask(hdmi, P2T_CTRL, P2T_DC_PKT_EN, P2T_DC_PKT_EN);
> +
> +	/* Enable HDMI/MHL mode for output */
> +	hdmi_writeb_mask(hdmi, TEST_TXCTRL, TEST_TXCTRL_HDMI_MODE,
> +			 TEST_TXCTRL_HDMI_MODE);
> +
> +	/* Configure reg_qc_sel */
> +	hdmi_writeb(hdmi, HDMICTL4, 0x3);
> +
> +	/* Enable interrupt */
> +	hdmi_writeb_mask(hdmi, INTR1_MASK, INTR1_MONITOR_DETECT,
> +			 INTR1_MONITOR_DETECT);
> +
> +	/* Clear reset for normal operation */
> +	hdmi_writeb(hdmi, PWD_SRST, 0);
> +
> +	/* Start up phy */
> +	zx_hdmi_phy_start(hdmi);
> +}
> +
> +static int zx_hdmi_bind(struct device *dev, struct device *master, void *data)
> +{
> +	struct platform_device *pdev = to_platform_device(dev);
> +	struct drm_device *drm = data;
> +	struct resource *res;
> +	struct zx_hdmi *hdmi;
> +	int irq;
> +	int ret;
> +
> +	hdmi = devm_kzalloc(dev, sizeof(*hdmi), GFP_KERNEL);
> +	if (!hdmi)
> +		return -ENOMEM;
> +
> +	hdmi->dev = dev;
> +	hdmi->drm = drm;
> +	hdmi->inf = &vou_inf_hdmi;
> +
> +	dev_set_drvdata(dev, hdmi);
> +
> +	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> +	hdmi->mmio = devm_ioremap_resource(dev, res);
> +	if (IS_ERR(hdmi->mmio)) {
> +		ret = PTR_ERR(hdmi->mmio);
> +		dev_err(dev, "failed to remap hdmi region: %d\n", ret);
> +		return ret;
> +	}
> +
> +	irq = platform_get_irq(pdev, 0);
> +	if (irq < 0)
> +		return irq;
> +
> +	hdmi->cec_clk = devm_clk_get(hdmi->dev, "osc_cec");
> +	if (IS_ERR(hdmi->cec_clk)) {
> +		ret = PTR_ERR(hdmi->cec_clk);
> +		dev_err(dev, "failed to get cec_clk: %d\n", ret);
> +		return ret;
> +	}
> +
> +	hdmi->osc_clk = devm_clk_get(hdmi->dev, "osc_clk");
> +	if (IS_ERR(hdmi->osc_clk)) {
> +		ret = PTR_ERR(hdmi->osc_clk);
> +		dev_err(dev, "failed to get osc_clk: %d\n", ret);
> +		return ret;
> +	}
> +
> +	hdmi->xclk = devm_clk_get(hdmi->dev, "xclk");
> +	if (IS_ERR(hdmi->xclk)) {
> +		ret = PTR_ERR(hdmi->xclk);
> +		dev_err(dev, "failed to get xclk: %d\n", ret);
> +		return ret;
> +	}
> +
> +	zx_hdmi_hw_init(hdmi);
> +
> +	ret = clk_prepare_enable(hdmi->cec_clk);
> +	if (ret) {
> +		dev_err(dev, "failed to enable cec_clk: %d\n", ret);
> +		return ret;
> +	}
> +
> +	ret = clk_prepare_enable(hdmi->osc_clk);
> +	if (ret) {
> +		dev_err(dev, "failed to enable osc_clk: %d\n", ret);
> +		goto disable_cec_clk;
> +	}
> +
> +	ret = clk_prepare_enable(hdmi->xclk);
> +	if (ret) {
> +		dev_err(dev, "failed to enable xclk: %d\n", ret);
> +		goto disable_osc_clk;
> +	}
> +
> +
> +	ret = zx_hdmi_ddc_register(hdmi);
> +	if (ret) {
> +		dev_err(dev, "failed to register ddc: %d\n", ret);
> +		goto disable_xclk;
> +	}
> +
> +	ret = zx_hdmi_register(drm, hdmi);
> +	if (ret) {
> +		dev_err(dev, "failed to register hdmi: %d\n", ret);
> +		goto disable_xclk;
> +	}
> +
> +	ret = devm_request_threaded_irq(dev, irq, zx_hdmi_irq_handler,
> +					zx_hdmi_irq_thread, IRQF_SHARED,
> +					dev_name(dev), hdmi);
> +	if (ret) {
> +		dev_err(dev, "failed to request threaded irq: %d\n", ret);
> +		goto disable_xclk;
> +	}
> +
> +	return 0;
> +
> +disable_xclk:
> +	clk_disable_unprepare(hdmi->xclk);
> +disable_osc_clk:
> +	clk_disable_unprepare(hdmi->osc_clk);
> +disable_cec_clk:
> +	clk_disable_unprepare(hdmi->cec_clk);
> +	return ret;
> +}
> +
> +static void zx_hdmi_unbind(struct device *dev, struct device *master,
> +			   void *data)
> +{
> +	struct zx_hdmi *hdmi = dev_get_drvdata(dev);
> +
> +	clk_disable_unprepare(hdmi->xclk);
> +	clk_disable_unprepare(hdmi->osc_clk);
> +	clk_disable_unprepare(hdmi->cec_clk);
> +}
> +
> +static const struct component_ops zx_hdmi_component_ops = {
> +	.bind = zx_hdmi_bind,
> +	.unbind = zx_hdmi_unbind,
> +};
> +
> +static int zx_hdmi_probe(struct platform_device *pdev)
> +{
> +	return component_add(&pdev->dev, &zx_hdmi_component_ops);
> +}
> +
> +static int zx_hdmi_remove(struct platform_device *pdev)
> +{
> +	component_del(&pdev->dev, &zx_hdmi_component_ops);
> +	return 0;
> +}
> +
> +static const struct of_device_id zx_hdmi_of_match[] = {
> +	{ .compatible = "zte,zx296718-hdmi", },
> +	{ /* end */ },
> +};
> +MODULE_DEVICE_TABLE(of, zx_hdmi_of_match);
> +
> +struct platform_driver zx_hdmi_driver = {
> +	.probe = zx_hdmi_probe,
> +	.remove = zx_hdmi_remove,
> +	.driver	= {
> +		.name = "zx-hdmi",
> +		.of_match_table	= zx_hdmi_of_match,
> +	},
> +};
> diff --git a/drivers/gpu/drm/zte/zx_plane.c b/drivers/gpu/drm/zte/zx_plane.c
> new file mode 100644
> index 000000000000..fdab1715bee5
> --- /dev/null
> +++ b/drivers/gpu/drm/zte/zx_plane.c
> @@ -0,0 +1,375 @@
> +/*
> + * Copyright 2016 Linaro Ltd.
> + * Copyright 2016 ZTE Corporation.
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License version 2 as
> + * published by the Free Software Foundation.
> + *
> + */
> +
> +#include <drm/drm_atomic.h>
> +#include <drm/drm_atomic_helper.h>
> +#include <drm/drm_fb_cma_helper.h>
> +#include <drm/drm_gem_cma_helper.h>
> +#include <drm/drm_modeset_helper_vtables.h>
> +#include <drm/drm_plane_helper.h>
> +#include <drm/drmP.h>
> +
> +#include "zx_drm_drv.h"
> +#include "zx_plane.h"
> +#include "zx_vou.h"
> +
> +/* GL registers */
> +#define GL_CTRL0			0x00
> +#define GL_UPDATE			BIT(5)
> +#define GL_CTRL1			0x04
> +#define GL_DATA_FMT_SHIFT		0
> +#define GL_DATA_FMT_MASK		(0xf << GL_DATA_FMT_SHIFT)
> +#define GL_FMT_ARGB8888			0
> +#define GL_FMT_RGB888			1
> +#define GL_FMT_RGB565			2
> +#define GL_FMT_ARGB1555			3
> +#define GL_FMT_ARGB4444			4
> +#define GL_CTRL2			0x08
> +#define GL_GLOBAL_ALPHA_SHIFT		8
> +#define GL_GLOBAL_ALPHA_MASK		(0xff << GL_GLOBAL_ALPHA_SHIFT)
> +#define GL_CTRL3			0x0c
> +#define GL_SCALER_BYPASS_MODE		BIT(0)
> +#define GL_STRIDE			0x18
> +#define GL_ADDR				0x1c
> +#define GL_SRC_SIZE			0x38
> +#define GL_SRC_W_SHIFT			16
> +#define GL_SRC_W_MASK			(0x3fff << GL_SRC_W_SHIFT)
> +#define GL_SRC_H_SHIFT			0
> +#define GL_SRC_H_MASK			(0x3fff << GL_SRC_H_SHIFT)
> +#define GL_POS_START			0x9c
> +#define GL_POS_END			0xa0
> +#define GL_POS_X_SHIFT			16
> +#define GL_POS_X_MASK			(0x1fff << GL_POS_X_SHIFT)
> +#define GL_POS_Y_SHIFT			0
> +#define GL_POS_Y_MASK			(0x1fff << GL_POS_Y_SHIFT)
> +
> +#define GL_SRC_W(x)	(((x) << GL_SRC_W_SHIFT) & GL_SRC_W_MASK)
> +#define GL_SRC_H(x)	(((x) << GL_SRC_H_SHIFT) & GL_SRC_H_MASK)
> +#define GL_POS_X(x)	(((x) << GL_POS_X_SHIFT) & GL_POS_X_MASK)
> +#define GL_POS_Y(x)	(((x) << GL_POS_Y_SHIFT) & GL_POS_Y_MASK)
> +
> +/* CSC registers */
> +#define CSC_CTRL0			0x30
> +#define CSC_COV_MODE_SHIFT		16
> +#define CSC_COV_MODE_MASK		(0xffff << CSC_COV_MODE_SHIFT)
> +#define CSC_BT601_IMAGE_RGB2YCBCR	0
> +#define CSC_BT601_IMAGE_YCBCR2RGB	1
> +#define CSC_BT601_VIDEO_RGB2YCBCR	2
> +#define CSC_BT601_VIDEO_YCBCR2RGB	3
> +#define CSC_BT709_IMAGE_RGB2YCBCR	4
> +#define CSC_BT709_IMAGE_YCBCR2RGB	5
> +#define CSC_BT709_VIDEO_RGB2YCBCR	6
> +#define CSC_BT709_VIDEO_YCBCR2RGB	7
> +#define CSC_BT2020_IMAGE_RGB2YCBCR	8
> +#define CSC_BT2020_IMAGE_YCBCR2RGB	9
> +#define CSC_BT2020_VIDEO_RGB2YCBCR	10
> +#define CSC_BT2020_VIDEO_YCBCR2RGB	11
> +#define CSC_WORK_ENABLE			BIT(0)
> +
> +/* RSZ registers */
> +#define RSZ_SRC_CFG			0x00
> +#define RSZ_DEST_CFG			0x04
> +#define RSZ_ENABLE_CFG			0x14
> +
> +#define RSZ_VER_SHIFT			16
> +#define RSZ_VER_MASK			(0xffff << RSZ_VER_SHIFT)
> +#define RSZ_HOR_SHIFT			0
> +#define RSZ_HOR_MASK			(0xffff << RSZ_HOR_SHIFT)
> +
> +#define RSZ_VER(x)	(((x) << RSZ_VER_SHIFT) & RSZ_VER_MASK)
> +#define RSZ_HOR(x)	(((x) << RSZ_HOR_SHIFT) & RSZ_HOR_MASK)
> +
> +/* HBSC registers */
> +#define HBSC_SATURATION			0x00
> +#define HBSC_HUE			0x04
> +#define HBSC_BRIGHT			0x08
> +#define HBSC_CONTRAST			0x0c
> +#define HBSC_THRESHOLD_COL1		0x10
> +#define HBSC_THRESHOLD_COL2		0x14
> +#define HBSC_THRESHOLD_COL3		0x18
> +#define HBSC_CTRL0			0x28
> +#define HBSC_CTRL_EN			BIT(2)
> +
> +struct zx_plane {
> +	struct drm_plane plane;
> +	void __iomem *layer;
> +	void __iomem *csc;
> +	void __iomem *hbsc;
> +	void __iomem *rsz;
> +};
> +
> +#define to_zx_plane(plane)	container_of(plane, struct zx_plane, plane)
> +
> +static const uint32_t gl_formats[] = {
> +	DRM_FORMAT_ARGB8888,
> +	DRM_FORMAT_XRGB8888,
> +	DRM_FORMAT_RGB888,
> +	DRM_FORMAT_RGB565,
> +	DRM_FORMAT_ARGB1555,
> +	DRM_FORMAT_ARGB4444,
> +};
> +
> +static int zx_gl_plane_atomic_check(struct drm_plane *plane,
> +				    struct drm_plane_state *plane_state)
> +{
> +	struct drm_framebuffer *fb = plane_state->fb;
> +	struct drm_crtc *crtc = plane_state->crtc;
> +	struct drm_crtc_state *crtc_state;
> +	struct drm_rect clip;
> +
> +	if (!crtc || !fb)
> +		return 0;
> +
> +	crtc_state = drm_atomic_get_existing_crtc_state(plane_state->state,
> +							crtc);
> +	if (WARN_ON(!crtc_state))
> +		return -EINVAL;
> +
> +	/* plane must match crtc enable state */
> +	if (crtc_state->enable != !!plane_state->crtc)
> +		return -EINVAL;
> +
> +	/* nothing to check when disabling or disabled */
> +	if (!crtc_state->enable)
> +		return 0;
> +
> +	clip.x1 = 0;
> +	clip.y1 = 0;
> +	clip.x2 = crtc_state->adjusted_mode.hdisplay;
> +	clip.y2 = crtc_state->adjusted_mode.vdisplay;
> +
> +	return drm_plane_helper_check_state(plane_state, &clip,
> +					    DRM_PLANE_HELPER_NO_SCALING,
> +					    DRM_PLANE_HELPER_NO_SCALING,
> +					    false, true);
> +}
> +
> +static int zx_gl_get_fmt(uint32_t format)
> +{
> +	switch (format) {
> +	case DRM_FORMAT_ARGB8888:
> +	case DRM_FORMAT_XRGB8888:
> +		return GL_FMT_ARGB8888;
> +	case DRM_FORMAT_RGB888:
> +		return GL_FMT_RGB888;
> +	case DRM_FORMAT_RGB565:
> +		return GL_FMT_RGB565;
> +	case DRM_FORMAT_ARGB1555:
> +		return GL_FMT_ARGB1555;
> +	case DRM_FORMAT_ARGB4444:
> +		return GL_FMT_ARGB4444;
> +	default:
> +		WARN_ONCE(1, "invalid pixel format %d\n", format);
> +		return -EINVAL;
> +	}
> +}
> +
> +static inline void zx_gl_set_update(struct zx_plane *zplane)
> +{
> +	void __iomem *layer = zplane->layer;
> +
> +	zx_writel_mask(layer + GL_CTRL0, GL_UPDATE, GL_UPDATE);
> +}
> +
> +static inline void zx_gl_rsz_set_update(struct zx_plane *zplane)
> +{
> +	zx_writel(zplane->rsz + RSZ_ENABLE_CFG, 1);
> +}
> +
> +void zx_plane_set_update(struct drm_plane *plane)
> +{
> +	struct zx_plane *zplane = to_zx_plane(plane);
> +
> +	zx_gl_rsz_set_update(zplane);
> +	zx_gl_set_update(zplane);
> +}
> +
> +static void zx_gl_rsz_setup(struct zx_plane *zplane, u32 src_w, u32 src_h,
> +			    u32 dst_w, u32 dst_h)
> +{
> +	void __iomem *rsz = zplane->rsz;
> +
> +	zx_writel(rsz + RSZ_SRC_CFG, RSZ_VER(src_h - 1) | RSZ_HOR(src_w - 1));
> +	zx_writel(rsz + RSZ_DEST_CFG, RSZ_VER(dst_h - 1) | RSZ_HOR(dst_w - 1));
> +
> +	zx_gl_rsz_set_update(zplane);
> +}
> +
> +static void zx_gl_plane_atomic_update(struct drm_plane *plane,
> +				      struct drm_plane_state *old_state)
> +{
> +	struct zx_plane *zplane = to_zx_plane(plane);
> +	struct drm_framebuffer *fb = plane->state->fb;
> +	struct drm_gem_cma_object *cma_obj;
> +	void __iomem *layer = zplane->layer;
> +	void __iomem *csc = zplane->csc;
> +	void __iomem *hbsc = zplane->hbsc;
> +	u32 src_x, src_y, src_w, src_h;
> +	u32 dst_x, dst_y, dst_w, dst_h;
> +	unsigned int depth, bpp;
> +	uint32_t format;
> +	dma_addr_t paddr;
> +	u32 stride;
> +	int fmt;
> +
> +	if (!fb)
> +		return;
> +
> +	format = fb->pixel_format;
> +	stride = fb->pitches[0];
> +
> +	src_x = plane->state->src_x >> 16;
> +	src_y = plane->state->src_y >> 16;
> +	src_w = plane->state->src_w >> 16;
> +	src_h = plane->state->src_h >> 16;
> +
> +	dst_x = plane->state->crtc_x;
> +	dst_y = plane->state->crtc_y;
> +	dst_w = plane->state->crtc_w;
> +	dst_h = plane->state->crtc_h;
> +
> +	drm_fb_get_bpp_depth(format, &depth, &bpp);
> +
> +	cma_obj = drm_fb_cma_get_gem_obj(fb, 0);
> +	paddr = cma_obj->paddr + fb->offsets[0];
> +	paddr += src_y * stride + src_x * bpp / 8;
> +	zx_writel(layer + GL_ADDR, paddr);
> +
> +	/* Set up source height/width register */
> +	zx_writel(layer + GL_SRC_SIZE, GL_SRC_W(src_w) | GL_SRC_H(src_h));
> +
> +	/* Set up start position register */
> +	zx_writel(layer + GL_POS_START, GL_POS_X(dst_x) | GL_POS_Y(dst_y));
> +
> +	/* Set up end position register */
> +	zx_writel(layer + GL_POS_END,
> +		  GL_POS_X(dst_x + dst_w) | GL_POS_Y(dst_y + dst_h));
> +
> +	/* Set up stride register */
> +	zx_writel(layer + GL_STRIDE, stride & 0xffff);
> +
> +	/* Set up graphic layer data format */
> +	fmt = zx_gl_get_fmt(format);
> +	if (fmt >= 0)
> +		zx_writel_mask(layer + GL_CTRL1, GL_DATA_FMT_MASK,
> +			       fmt << GL_DATA_FMT_SHIFT);
> +
> +	/* Initialize global alpha with a sane value */
> +	zx_writel_mask(layer + GL_CTRL2, GL_GLOBAL_ALPHA_MASK,
> +		       0xff << GL_GLOBAL_ALPHA_SHIFT);
> +
> +	/* Setup CSC for the GL */
> +	if (dst_h > 720)
> +		zx_writel_mask(csc + CSC_CTRL0, CSC_COV_MODE_MASK,
> +			       CSC_BT709_IMAGE_RGB2YCBCR << CSC_COV_MODE_SHIFT);
> +	else
> +		zx_writel_mask(csc + CSC_CTRL0, CSC_COV_MODE_MASK,
> +			       CSC_BT601_IMAGE_RGB2YCBCR << CSC_COV_MODE_SHIFT);
> +	zx_writel_mask(csc + CSC_CTRL0, CSC_WORK_ENABLE, CSC_WORK_ENABLE);
> +
> +	/* Always use scaler since it exists (set for not bypass) */
> +	zx_writel_mask(layer + GL_CTRL3, GL_SCALER_BYPASS_MODE,
> +		       GL_SCALER_BYPASS_MODE);
> +
> +	zx_gl_rsz_setup(zplane, src_w, src_h, dst_w, dst_h);
> +
> +	/* Enable HBSC block */
> +	zx_writel_mask(hbsc + HBSC_CTRL0, HBSC_CTRL_EN, HBSC_CTRL_EN);
> +
> +	zx_gl_set_update(zplane);
> +}
> +
> +static const struct drm_plane_helper_funcs zx_gl_plane_helper_funcs = {
> +	.atomic_check = zx_gl_plane_atomic_check,
> +	.atomic_update = zx_gl_plane_atomic_update,
> +};
> +
> +static void zx_plane_destroy(struct drm_plane *plane)
> +{
> +	drm_plane_helper_disable(plane);
> +	drm_plane_cleanup(plane);
> +}
> +
> +static const struct drm_plane_funcs zx_plane_funcs = {
> +	.update_plane = drm_atomic_helper_update_plane,
> +	.disable_plane = drm_atomic_helper_disable_plane,
> +	.destroy = zx_plane_destroy,
> +	.reset = drm_atomic_helper_plane_reset,
> +	.atomic_duplicate_state = drm_atomic_helper_plane_duplicate_state,
> +	.atomic_destroy_state = drm_atomic_helper_plane_destroy_state,
> +};
> +
> +static void zx_plane_hbsc_init(struct zx_plane *zplane)
> +{
> +	void __iomem *hbsc = zplane->hbsc;
> +
> +	/*
> +	 *  Initialize HBSC block with a sane configuration per recommedation
> +	 *  from ZTE BSP code.
> +	 */
> +	zx_writel(hbsc + HBSC_SATURATION, 0x200);
> +	zx_writel(hbsc + HBSC_HUE, 0x0);
> +	zx_writel(hbsc + HBSC_BRIGHT, 0x0);
> +	zx_writel(hbsc + HBSC_CONTRAST, 0x200);
> +
> +	zx_writel(hbsc + HBSC_THRESHOLD_COL1, (0x3ac << 16) | 0x40);
> +	zx_writel(hbsc + HBSC_THRESHOLD_COL2, (0x3c0 << 16) | 0x40);
> +	zx_writel(hbsc + HBSC_THRESHOLD_COL3, (0x3c0 << 16) | 0x40);
> +}
> +
> +struct drm_plane *zx_plane_init(struct drm_device *drm, struct device *dev,
> +				struct zx_layer_data *data,
> +				enum drm_plane_type type)
> +{
> +	const struct drm_plane_helper_funcs *helper;
> +	struct zx_plane *zplane;
> +	struct drm_plane *plane;
> +	const uint32_t *formats;
> +	unsigned int format_count;
> +	int ret;
> +
> +	zplane = devm_kzalloc(dev, sizeof(*zplane), GFP_KERNEL);
> +	if (!zplane)
> +		return ERR_PTR(-ENOMEM);
> +
> +	plane = &zplane->plane;
> +
> +	zplane->layer = data->layer;
> +	zplane->hbsc = data->hbsc;
> +	zplane->csc = data->csc;
> +	zplane->rsz = data->rsz;
> +
> +	zx_plane_hbsc_init(zplane);
> +
> +	switch (type) {
> +	case DRM_PLANE_TYPE_PRIMARY:
> +		helper = &zx_gl_plane_helper_funcs;
> +		formats = gl_formats;
> +		format_count = ARRAY_SIZE(gl_formats);
> +		break;
> +	case DRM_PLANE_TYPE_OVERLAY:
> +		/* TODO: add video layer (vl) support */
> +		break;
> +	default:
> +		return ERR_PTR(-ENODEV);
> +	}
> +
> +	ret = drm_universal_plane_init(drm, plane, VOU_CRTC_MASK,
> +				       &zx_plane_funcs, formats, format_count,
> +				       type, NULL);
> +	if (ret) {
> +		dev_err(dev, "failed to init universal plane: %d\n", ret);
> +		return ERR_PTR(ret);
> +	}
> +
> +	drm_plane_helper_add(plane, helper);
> +
> +	return plane;
> +}
> diff --git a/drivers/gpu/drm/zte/zx_plane.h b/drivers/gpu/drm/zte/zx_plane.h
> new file mode 100644
> index 000000000000..2b82cd558d9d
> --- /dev/null
> +++ b/drivers/gpu/drm/zte/zx_plane.h
> @@ -0,0 +1,26 @@
> +/*
> + * Copyright 2016 Linaro Ltd.
> + * Copyright 2016 ZTE Corporation.
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License version 2 as
> + * published by the Free Software Foundation.
> + *
> + */
> +
> +#ifndef __ZX_PLANE_H__
> +#define __ZX_PLANE_H__
> +
> +struct zx_layer_data {
> +	void __iomem *layer;
> +	void __iomem *csc;
> +	void __iomem *hbsc;
> +	void __iomem *rsz;
> +};
> +
> +struct drm_plane *zx_plane_init(struct drm_device *drm, struct device *dev,
> +				struct zx_layer_data *data,
> +				enum drm_plane_type type);
> +void zx_plane_set_update(struct drm_plane *plane);
> +
> +#endif /* __ZX_PLANE_H__ */
> diff --git a/drivers/gpu/drm/zte/zx_vou.c b/drivers/gpu/drm/zte/zx_vou.c
> new file mode 100644
> index 000000000000..676c750d6009
> --- /dev/null
> +++ b/drivers/gpu/drm/zte/zx_vou.c
> @@ -0,0 +1,799 @@
> +/*
> + * Copyright 2016 Linaro Ltd.
> + * Copyright 2016 ZTE Corporation.
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License version 2 as
> + * published by the Free Software Foundation.
> + *
> + */
> +
> +#include <linux/clk.h>
> +#include <linux/component.h>
> +#include <linux/of_address.h>
> +#include <video/videomode.h>
> +
> +#include <drm/drm_atomic_helper.h>
> +#include <drm/drm_crtc.h>
> +#include <drm/drm_crtc_helper.h>
> +#include <drm/drm_fb_cma_helper.h>
> +#include <drm/drm_fb_helper.h>
> +#include <drm/drm_gem_cma_helper.h>
> +#include <drm/drm_of.h>
> +#include <drm/drm_plane_helper.h>
> +#include <drm/drmP.h>
> +
> +#include "zx_drm_drv.h"
> +#include "zx_plane.h"
> +#include "zx_vou.h"
> +
> +/* Sub-module offset */
> +#define MAIN_GL_OFFSET			0x130
> +#define MAIN_CSC_OFFSET			0x580
> +#define MAIN_HBSC_OFFSET		0x820
> +#define MAIN_RSZ_OFFSET			0x600 /* OTFPPU sub-module */
> +
> +#define AUX_GL_OFFSET			0x200
> +#define AUX_CSC_OFFSET			0x5d0
> +#define AUX_HBSC_OFFSET			0x860
> +#define AUX_RSZ_OFFSET			0x800
> +
> +/* OSD (GPC_GLOBAL) registers */
> +#define OSD_INT_STA			0x04
> +#define OSD_INT_CLRSTA			0x08
> +#define OSD_INT_MSK			0x0c
> +#define OSD_INT_AUX_UPT			BIT(14)
> +#define OSD_INT_MAIN_UPT		BIT(13)
> +#define OSD_INT_GL1_LBW			BIT(10)
> +#define OSD_INT_GL0_LBW			BIT(9)
> +#define OSD_INT_VL2_LBW			BIT(8)
> +#define OSD_INT_VL1_LBW			BIT(7)
> +#define OSD_INT_VL0_LBW			BIT(6)
> +#define OSD_INT_BUS_ERR			BIT(3)
> +#define OSD_INT_CFG_ERR			BIT(2)
> +#define OSD_INT_ERROR (\
> +	OSD_INT_GL1_LBW | OSD_INT_GL0_LBW | \
> +	OSD_INT_VL2_LBW | OSD_INT_VL1_LBW | OSD_INT_VL0_LBW | \
> +	OSD_INT_BUS_ERR | OSD_INT_CFG_ERR \
> +)
> +#define OSD_INT_ENABLE (OSD_INT_ERROR | OSD_INT_AUX_UPT | OSD_INT_MAIN_UPT)
> +#define OSD_CTRL0			0x10
> +#define OSD_CTRL0_GL0_EN		BIT(7)
> +#define OSD_CTRL0_GL0_SEL		BIT(6)
> +#define OSD_CTRL0_GL1_EN		BIT(5)
> +#define OSD_CTRL0_GL1_SEL		BIT(4)
> +#define OSD_RST_CLR			0x1c
> +#define RST_PER_FRAME			BIT(19)
> +
> +/* Main/Aux channel registers */
> +#define OSD_MAIN_CHN			0x470
> +#define OSD_AUX_CHN			0x4d0
> +#define CHN_CTRL0			0x00
> +#define CHN_ENABLE			BIT(0)
> +#define CHN_CTRL1			0x04
> +#define CHN_SCREEN_W_SHIFT		18
> +#define CHN_SCREEN_W_MASK		(0x1fff << CHN_SCREEN_W_SHIFT)
> +#define CHN_SCREEN_H_SHIFT		5
> +#define CHN_SCREEN_H_MASK		(0x1fff << CHN_SCREEN_H_SHIFT)
> +#define CHN_UPDATE			0x08
> +
> +/* TIMING_CTRL registers */
> +#define TIMING_TC_ENABLE		0x04
> +#define AUX_TC_EN			BIT(1)
> +#define MAIN_TC_EN			BIT(0)
> +#define FIR_MAIN_ACTIVE			0x08
> +#define FIR_AUX_ACTIVE			0x0c
> +#define V_ACTIVE_SHIFT			16
> +#define V_ACTIVE_MASK			(0xffff << V_ACTIVE_SHIFT)
> +#define H_ACTIVE_SHIFT			0
> +#define H_ACTIVE_MASK			(0xffff << H_ACTIVE_SHIFT)
> +#define FIR_MAIN_H_TIMING		0x10
> +#define FIR_MAIN_V_TIMING		0x14
> +#define FIR_AUX_H_TIMING		0x18
> +#define FIR_AUX_V_TIMING		0x1c
> +#define SYNC_WIDE_SHIFT			22
> +#define SYNC_WIDE_MASK			(0x3ff << SYNC_WIDE_SHIFT)
> +#define BACK_PORCH_SHIFT		11
> +#define BACK_PORCH_MASK			(0x7ff << BACK_PORCH_SHIFT)
> +#define FRONT_PORCH_SHIFT		0
> +#define FRONT_PORCH_MASK		(0x7ff << FRONT_PORCH_SHIFT)
> +#define TIMING_CTRL			0x20
> +#define AUX_POL_SHIFT			3
> +#define AUX_POL_MASK			(0x7 << AUX_POL_SHIFT)
> +#define MAIN_POL_SHIFT			0
> +#define MAIN_POL_MASK			(0x7 << MAIN_POL_SHIFT)
> +#define POL_DE_SHIFT			2
> +#define POL_VSYNC_SHIFT			1
> +#define POL_HSYNC_SHIFT			0
> +#define TIMING_INT_CTRL			0x24
> +#define TIMING_INT_STATE		0x28
> +#define TIMING_INT_AUX_FRAME		BIT(3)
> +#define TIMING_INT_MAIN_FRAME		BIT(1)
> +#define TIMING_INT_AUX_FRAME_SEL_VSW	(0x2 << 10)
> +#define TIMING_INT_MAIN_FRAME_SEL_VSW	(0x2 << 6)
> +#define TIMING_INT_ENABLE (\
> +	TIMING_INT_MAIN_FRAME_SEL_VSW | TIMING_INT_AUX_FRAME_SEL_VSW | \
> +	TIMING_INT_MAIN_FRAME | TIMING_INT_AUX_FRAME \
> +)
> +#define TIMING_MAIN_SHIFT		0x2c
> +#define TIMING_AUX_SHIFT		0x30
> +#define H_SHIFT_VAL			0x0048
> +#define TIMING_MAIN_PI_SHIFT		0x68
> +#define TIMING_AUX_PI_SHIFT		0x6c
> +#define H_PI_SHIFT_VAL			0x000f
> +
> +#define V_ACTIVE(x)	(((x) << V_ACTIVE_SHIFT) & V_ACTIVE_MASK)
> +#define H_ACTIVE(x)	(((x) << H_ACTIVE_SHIFT) & H_ACTIVE_MASK)
> +
> +#define SYNC_WIDE(x)	(((x) << SYNC_WIDE_SHIFT) & SYNC_WIDE_MASK)
> +#define BACK_PORCH(x)	(((x) << BACK_PORCH_SHIFT) & BACK_PORCH_MASK)
> +#define FRONT_PORCH(x)	(((x) << FRONT_PORCH_SHIFT) & FRONT_PORCH_MASK)
> +
> +/* DTRC registers */
> +#define DTRC_F0_CTRL			0x2c
> +#define DTRC_F1_CTRL			0x5c
> +#define DTRC_DECOMPRESS_BYPASS		BIT(17)
> +#define DTRC_DETILE_CTRL		0x68
> +#define TILE2RASTESCAN_BYPASS_MODE	BIT(30)
> +#define DETILE_ARIDR_MODE_MASK		(0x3 << 0)
> +#define DETILE_ARID_ALL			0
> +#define DETILE_ARID_IN_ARIDR		1
> +#define DETILE_ARID_BYP_BUT_ARIDR	2
> +#define DETILE_ARID_IN_ARIDR2		3
> +#define DTRC_ARID			0x6c
> +#define DTRC_ARID3_SHIFT		24
> +#define DTRC_ARID3_MASK			(0xff << DTRC_ARID3_SHIFT)
> +#define DTRC_ARID2_SHIFT		16
> +#define DTRC_ARID2_MASK			(0xff << DTRC_ARID2_SHIFT)
> +#define DTRC_ARID1_SHIFT		8
> +#define DTRC_ARID1_MASK			(0xff << DTRC_ARID1_SHIFT)
> +#define DTRC_ARID0_SHIFT		0
> +#define DTRC_ARID0_MASK			(0xff << DTRC_ARID0_SHIFT)
> +#define DTRC_DEC2DDR_ARID		0x70
> +
> +#define DTRC_ARID3(x)	(((x) << DTRC_ARID3_SHIFT) & DTRC_ARID3_MASK)
> +#define DTRC_ARID2(x)	(((x) << DTRC_ARID2_SHIFT) & DTRC_ARID2_MASK)
> +#define DTRC_ARID1(x)	(((x) << DTRC_ARID1_SHIFT) & DTRC_ARID1_MASK)
> +#define DTRC_ARID0(x)	(((x) << DTRC_ARID0_SHIFT) & DTRC_ARID0_MASK)
> +
> +/* VOU_CTRL registers */
> +#define VOU_INF_EN			0x00
> +#define VOU_INF_CH_SEL			0x04
> +#define VOU_INF_DATA_SEL		0x08
> +#define VOU_SOFT_RST			0x14
> +#define VOU_CLK_SEL			0x18
> +#define VOU_CLK_GL1_SEL			BIT(5)
> +#define VOU_CLK_GL0_SEL			BIT(4)
> +#define VOU_CLK_REQEN			0x20
> +#define VOU_CLK_EN			0x24
> +
> +/* OTFPPU_CTRL registers */
> +#define OTFPPU_RSZ_DATA_SOURCE		0x04
> +
> +#define GL_NUM				2
> +#define VL_NUM				3
> +
> +enum vou_chn_type {
> +	VOU_CHN_MAIN,
> +	VOU_CHN_AUX,
> +};
> +
> +struct zx_crtc_regs {
> +	u32 fir_active;
> +	u32 fir_htiming;
> +	u32 fir_vtiming;
> +	u32 timing_shift;
> +	u32 timing_pi_shift;
> +};
> +
> +static const struct zx_crtc_regs main_crtc_regs = {
> +	.fir_active = FIR_MAIN_ACTIVE,
> +	.fir_htiming = FIR_MAIN_H_TIMING,
> +	.fir_vtiming = FIR_MAIN_V_TIMING,
> +	.timing_shift = TIMING_MAIN_SHIFT,
> +	.timing_pi_shift = TIMING_MAIN_PI_SHIFT,
> +};
> +
> +static const struct zx_crtc_regs aux_crtc_regs = {
> +	.fir_active = FIR_AUX_ACTIVE,
> +	.fir_htiming = FIR_AUX_H_TIMING,
> +	.fir_vtiming = FIR_AUX_V_TIMING,
> +	.timing_shift = TIMING_AUX_SHIFT,
> +	.timing_pi_shift = TIMING_AUX_PI_SHIFT,
> +};
> +
> +struct zx_crtc_bits {
> +	u32 polarity_mask;
> +	u32 polarity_shift;
> +	u32 tc_enable;
> +	u32 gl_enable;
> +};
> +
> +static const struct zx_crtc_bits main_crtc_bits = {
> +	.polarity_mask = MAIN_POL_MASK,
> +	.polarity_shift = MAIN_POL_SHIFT,
> +	.tc_enable = MAIN_TC_EN,
> +	.gl_enable = OSD_CTRL0_GL0_EN,
> +};
> +
> +static const struct zx_crtc_bits aux_crtc_bits = {
> +	.polarity_mask = AUX_POL_MASK,
> +	.polarity_shift = AUX_POL_SHIFT,
> +	.tc_enable = AUX_TC_EN,
> +	.gl_enable = OSD_CTRL0_GL1_EN,
> +};
> +
> +struct zx_crtc {
> +	struct drm_crtc crtc;
> +	struct drm_plane *primary;
> +	struct zx_vou_hw *vou;
> +	void __iomem *chnreg;
> +	const struct zx_crtc_regs *regs;
> +	const struct zx_crtc_bits *bits;
> +	enum vou_chn_type chn_type;
> +	struct clk *pixclk;
> +};
> +
> +#define to_zx_crtc(x) container_of(x, struct zx_crtc, crtc)
> +
> +struct zx_vou_hw {
> +	struct device *dev;
> +	void __iomem *osd;
> +	void __iomem *timing;
> +	void __iomem *vouctl;
> +	void __iomem *otfppu;
> +	void __iomem *dtrc;
> +	struct clk *axi_clk;
> +	struct clk *ppu_clk;
> +	struct clk *main_clk;
> +	struct clk *aux_clk;
> +	struct zx_crtc *main_crtc;
> +	struct zx_crtc *aux_crtc;
> +};
> +
> +static inline struct zx_vou_hw *crtc_to_vou(struct drm_crtc *crtc)
> +{
> +	struct zx_crtc *zcrtc = to_zx_crtc(crtc);
> +
> +	return zcrtc->vou;
> +}
> +
> +void vou_inf_enable(const struct vou_inf *inf, struct drm_crtc *crtc)
> +{
> +	struct zx_crtc *zcrtc = to_zx_crtc(crtc);
> +	struct zx_vou_hw *vou = zcrtc->vou;
> +	bool is_main = zcrtc->chn_type == VOU_CHN_MAIN;
> +	u32 data_sel_shift = inf->id << 1;
> +
> +	/* Select data format */
> +	zx_writel_mask(vou->vouctl + VOU_INF_DATA_SEL, 0x3 << data_sel_shift,
> +		       inf->data_sel << data_sel_shift);
> +
> +	/* Select channel */
> +	zx_writel_mask(vou->vouctl + VOU_INF_CH_SEL, 0x1 << inf->id,
> +		       zcrtc->chn_type << inf->id);
> +
> +	/* Select interface clocks */
> +	zx_writel_mask(vou->vouctl + VOU_CLK_SEL, inf->clocks_sel_bits,
> +		       is_main ? 0 : inf->clocks_sel_bits);
> +
> +	/* Enable interface clocks */
> +	zx_writel_mask(vou->vouctl + VOU_CLK_EN, inf->clocks_en_bits,
> +		       inf->clocks_en_bits);
> +
> +	/* Enable the device */
> +	zx_writel_mask(vou->vouctl + VOU_INF_EN, 1 << inf->id, 1 << inf->id);
> +}
> +
> +void vou_inf_disable(const struct vou_inf *inf, struct drm_crtc *crtc)
> +{
> +	struct zx_vou_hw *vou = crtc_to_vou(crtc);
> +
> +	/* Disable the device */
> +	zx_writel_mask(vou->vouctl + VOU_INF_EN, 1 << inf->id, 0);
> +
> +	/* Disable interface clocks */
> +	zx_writel_mask(vou->vouctl + VOU_CLK_EN, inf->clocks_en_bits, 0);
> +}
> +
> +static inline void vou_chn_set_update(struct zx_crtc *zcrtc)
> +{
> +	zx_writel(zcrtc->chnreg + CHN_UPDATE, 1);
> +}
> +
> +static void zx_crtc_enable(struct drm_crtc *crtc)
> +{
> +	struct drm_display_mode *mode = &crtc->state->adjusted_mode;
> +	struct zx_crtc *zcrtc = to_zx_crtc(crtc);
> +	struct zx_vou_hw *vou = zcrtc->vou;
> +	const struct zx_crtc_regs *regs = zcrtc->regs;
> +	const struct zx_crtc_bits *bits = zcrtc->bits;
> +	struct videomode vm;
> +	u32 pol = 0;
> +	u32 val;
> +	int ret;
> +
> +	drm_display_mode_to_videomode(mode, &vm);
> +
> +	/* Set up timing parameters */
> +	val = V_ACTIVE(vm.vactive - 1);
> +	val |= H_ACTIVE(vm.hactive - 1);
> +	zx_writel(vou->timing + regs->fir_active, val);
> +
> +	val = SYNC_WIDE(vm.hsync_len - 1);
> +	val |= BACK_PORCH(vm.hback_porch - 1);
> +	val |= FRONT_PORCH(vm.hfront_porch - 1);
> +	zx_writel(vou->timing + regs->fir_htiming, val);
> +
> +	val = SYNC_WIDE(vm.vsync_len - 1);
> +	val |= BACK_PORCH(vm.vback_porch - 1);
> +	val |= FRONT_PORCH(vm.vfront_porch - 1);
> +	zx_writel(vou->timing + regs->fir_vtiming, val);
> +
> +	/* Set up polarities */
> +	if (vm.flags & DISPLAY_FLAGS_VSYNC_LOW)
> +		pol |= 1 << POL_VSYNC_SHIFT;
> +	if (vm.flags & DISPLAY_FLAGS_HSYNC_LOW)
> +		pol |= 1 << POL_HSYNC_SHIFT;
> +
> +	zx_writel_mask(vou->timing + TIMING_CTRL, bits->polarity_mask,
> +		       pol << bits->polarity_shift);
> +
> +	/* Setup SHIFT register by following what ZTE BSP does */
> +	zx_writel(vou->timing + regs->timing_shift, H_SHIFT_VAL);
> +	zx_writel(vou->timing + regs->timing_pi_shift, H_PI_SHIFT_VAL);
> +
> +	/* Enable TIMING_CTRL */
> +	zx_writel_mask(vou->timing + TIMING_TC_ENABLE, bits->tc_enable,
> +		       bits->tc_enable);
> +
> +	/* Configure channel screen size */
> +	zx_writel_mask(zcrtc->chnreg + CHN_CTRL1, CHN_SCREEN_W_MASK,
> +		       vm.hactive << CHN_SCREEN_W_SHIFT);
> +	zx_writel_mask(zcrtc->chnreg + CHN_CTRL1, CHN_SCREEN_H_MASK,
> +		       vm.vactive << CHN_SCREEN_H_SHIFT);
> +
> +	/* Update channel */
> +	vou_chn_set_update(zcrtc);
> +
> +	/* Enable channel */
> +	zx_writel_mask(zcrtc->chnreg + CHN_CTRL0, CHN_ENABLE, CHN_ENABLE);
> +
> +	/* Enable Graphic Layer */
> +	zx_writel_mask(vou->osd + OSD_CTRL0, bits->gl_enable,
> +		       bits->gl_enable);
> +
> +	drm_crtc_vblank_on(crtc);
> +
> +	ret = clk_set_rate(zcrtc->pixclk, mode->clock * 1000);
> +	if (ret) {
> +		dev_warn(vou->dev, "failed to set pixclk rate: %d\n", ret);

DRM_WARN

> +		return;
> +	}
> +
> +	ret = clk_prepare_enable(zcrtc->pixclk);
> +	if (ret)
> +		dev_warn(vou->dev, "failed to enable pixclk: %d\n", ret);
> +}
> +
> +static void zx_crtc_disable(struct drm_crtc *crtc)
> +{
> +	struct zx_crtc *zcrtc = to_zx_crtc(crtc);
> +	const struct zx_crtc_bits *bits = zcrtc->bits;
> +	struct zx_vou_hw *vou = zcrtc->vou;
> +
> +	clk_disable_unprepare(zcrtc->pixclk);
> +
> +	drm_crtc_vblank_off(crtc);
> +
> +	/* Disable Graphic Layer */
> +	zx_writel_mask(vou->osd + OSD_CTRL0, bits->gl_enable, 0);
> +
> +	/* Disable channel */
> +	zx_writel_mask(zcrtc->chnreg + CHN_CTRL0, CHN_ENABLE, 0);
> +
> +	/* Disable TIMING_CTRL */
> +	zx_writel_mask(vou->timing + TIMING_TC_ENABLE, bits->tc_enable, 0);
> +}
> +
> +static void zx_crtc_atomic_begin(struct drm_crtc *crtc,
> +				 struct drm_crtc_state *state)
> +{
> +	struct drm_pending_vblank_event *event = crtc->state->event;
> +
> +	if (!event)
> +		return;
> +
> +	crtc->state->event = NULL;
> +
> +	spin_lock_irq(&crtc->dev->event_lock);
> +	if (drm_crtc_vblank_get(crtc) == 0)
> +		drm_crtc_arm_vblank_event(crtc, event);
> +	else
> +		drm_crtc_send_vblank_event(crtc, event);
> +	spin_unlock_irq(&crtc->dev->event_lock);

I think you may want to send the vblank event to userspace after you
commit your planes, and not before.

> +}
> +
> +static const struct drm_crtc_helper_funcs zx_crtc_helper_funcs = {
> +	.enable = zx_crtc_enable,
> +	.disable = zx_crtc_disable,
> +	.atomic_begin = zx_crtc_atomic_begin,
> +};
> +
> +static const struct drm_crtc_funcs zx_crtc_funcs = {
> +	.destroy = drm_crtc_cleanup,
> +	.set_config = drm_atomic_helper_set_config,
> +	.page_flip = drm_atomic_helper_page_flip,
> +	.reset = drm_atomic_helper_crtc_reset,
> +	.atomic_duplicate_state = drm_atomic_helper_crtc_duplicate_state,
> +	.atomic_destroy_state = drm_atomic_helper_crtc_destroy_state,
> +};
> +
> +static int zx_crtc_init(struct drm_device *drm, struct zx_vou_hw *vou,
> +			enum vou_chn_type chn_type)
> +{
> +	struct device *dev = vou->dev;
> +	struct zx_layer_data data;
> +	struct zx_crtc *zcrtc;
> +	int ret;
> +
> +	zcrtc = devm_kzalloc(dev, sizeof(*zcrtc), GFP_KERNEL);
> +	if (!zcrtc)
> +		return -ENOMEM;
> +
> +	zcrtc->vou = vou;
> +	zcrtc->chn_type = chn_type;
> +
> +	if (chn_type == VOU_CHN_MAIN) {
> +		data.layer = vou->osd + MAIN_GL_OFFSET;
> +		data.csc = vou->osd + MAIN_CSC_OFFSET;
> +		data.hbsc = vou->osd + MAIN_HBSC_OFFSET;
> +		data.rsz = vou->otfppu + MAIN_RSZ_OFFSET;
> +		zcrtc->chnreg = vou->osd + OSD_MAIN_CHN;
> +		zcrtc->regs = &main_crtc_regs;
> +		zcrtc->bits = &main_crtc_bits;
> +	} else {
> +		data.layer = vou->osd + AUX_GL_OFFSET;
> +		data.csc = vou->osd + AUX_CSC_OFFSET;
> +		data.hbsc = vou->osd + AUX_HBSC_OFFSET;
> +		data.rsz = vou->otfppu + AUX_RSZ_OFFSET;
> +		zcrtc->chnreg = vou->osd + OSD_AUX_CHN;
> +		zcrtc->regs = &aux_crtc_regs;
> +		zcrtc->bits = &aux_crtc_bits;
> +	}
> +
> +	zcrtc->pixclk = devm_clk_get(dev, (chn_type == VOU_CHN_MAIN) ?
> +					  "main_wclk" : "aux_wclk");
> +	if (IS_ERR(zcrtc->pixclk)) {
> +		ret = PTR_ERR(zcrtc->pixclk);
> +		dev_err(dev, "failed to get pix clk: %d\n", ret);

DRM_ERROR() - here and in other places in your patch

^ permalink raw reply

* Handling of enet_out on i.MX28
From: Andy Duan @ 2016-10-20 12:29 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20161020091126.jdoexu6iuu3jjzsm@pengutronix.de>

From: Uwe Kleine-K?nig <u.kleine-koenig@pengutronix.de> Sent: Thursday, October 20, 2016 5:11 PM
> To: Andy Duan <fugang.duan@nxp.com>; Fabio Estevam Estevam
> <fabio.estevam@nxp.com>; Shawn Guo <shawnguo@kernel.org>;
> devicetree at vger.kernel.org
> Cc: kernel at pengutronix.de; linux-arm-kernel at lists.infradead.org
> Subject: Handling of enet_out on i.MX28
> 
> Hello,
> 
> The i.MX28 reference manual specifies for HW_CLKCTRL_ENET.CLK_OUT_EN:
> "NOTE: This bit must be configured before ENET PLL is enabled.".
> 
> Currently this is not implemented: ENET PLL (aka pll2) is the parent of
> enet_out and so common clk enables the PLL first and only then sets
> HW_CLKCTRL_ENET.CLK_OUT_EN.
> 
> For now this is a theoretical problem because I don't see any issues. I only
> notice the discrepancy between manual and reality.
> 
> Do you think this is a problem?
> 
I don't know the history. But I think this is a problem. Maybe it bring some clock glitch that may cause PHY (with RMII)  abnormal.

> Apart from that I'm not happy with the handling of this clk. IMHO it should
> better be called "enet-ref" or similar (for the fec). imx28.dtsi specifies that
> the clk is in use[1] and if my machine doesn't I have to
> do:
> 
> 	&mac0 {
> 		...
> 		/* overwrite clocks and clock-names to remove enet_out */
> 		clocks = <&clks 57>, <&clks 57>;
> 		clock-names = "ipg", "ahb";
> 		...
> 	};
> 
> in my board.dts. This is ugly because I have to repeat stuff that is already in
> imx28.dtsi and it's not understandable without the comment.
> 
> It would be nice if dtc allowed to modify an array, then we could do:
> 
> 	clocks += <&clks 64>;
> 	clock-names = += "enet_out";
> 
> (assuming the included dtsi doesn't specify this clock).
> 
> I first though it would be a good idea to specify the enet-ref clk as
> follows:
> 
> 	&mac0 {
> 		...
> 		mdio {
> 			clocks = <&clks 64>;
> 			clock-names = "enet-ref";
> 			...
> 		};
> 	};
>
In RMII mode,  this clock is for phy and MAC reference clock.
It is better to specify this clock as "enet_clk_ref" and "enet_out" that is easy to understand.
In dtsi file, we can just define ipg and ahb clock.
clocks = <&clks 57>, <&clks 57>;
clock-names = "ipg","ahb";
In dts file, different boards may have design mode like RMII/MII, RMII mode needs to define enet_out and enet_clk_ref,  MII mode doesn't need this clocks.
So it depends on board design, we can overwrite the clock in dts board file.   
Like in RMII mode: 
clocks = <&clks 57>, <&clks 57>, <&clks 64>, <&clks 64>;
clock-names = "ipg","ahb", "enet_clk_ref","enet_out";
In MII mode: no necessary to overwrite them. 

> but while this makes it easier for the board.dts to add (or remove) it, it's not
> really right this way because the reference clock is needed for data RX and TX,
> not the mdio bus. Technically these are two different buses even though the
> "passengers" are often the same. (Even if two MACs are in use, the enet-ref
> signal is shared.)
> 
> What do you think?
> 
> Best regards
> Uwe
> 
> [1] clocks = <&clks 57>, <&clks 57>, <&clks 64>; clock-names = "ipg",
>     "ahb", "enet_out"; in &mac0.
> 
> --
> Pengutronix e.K.                           | Uwe Kleine-K?nig            |
> Industrial Linux Solutions                 | http://www.pengutronix.de/  |

^ permalink raw reply

* [PATCH 2/2] arm64/numa: fix incorrect print of end_pfn
From: Hanjun Guo @ 2016-10-20 12:21 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20161020105130.GD24914@arm.com>

On 2016/10/20 18:51, Will Deacon wrote:
> On Thu, Oct 20, 2016 at 11:52:56AM +0800, Hanjun Guo wrote:
>> From: Hanjun Guo <hanjun.guo@linaro.org>
>>
>> When booting on NUMA system with memory-less node (no
>> memory dimm on this memory controller), the print
>> for setup_node_data() is incorrect:
>>
>> NUMA: Initmem setup node 2 [mem 0x00000000-0xffffffffffffffff]
>>
>> It should be 0, not 0xffffffffffffffff as there is
>> no memory on that node.
> Wouldn't it make more sense to print something useful, like "memory-less
> node"?

in the log,

[    0.000000] NUMA: Initmem setup node 0 [mem 0x00000000-0x13fbffffff]
[    0.000000] NUMA: NODE_DATA [mem 0x13fbffe500-0x13fbffffff]
[    0.000000] NUMA: Initmem setup node 1 [mem 0x1400000000-0x17fbffffff]
[    0.000000] NUMA: NODE_DATA [mem 0x17fbfec500-0x17fbfedfff]
[    0.000000] NUMA: Initmem setup node 2 [mem 0x00000000-0xffffffffffffffff]
[    0.000000] NUMA: NODE_DATA [mem 0x17fbfeaa00-0x17fbfec4ff]
[    0.000000] NUMA: NODE_DATA(2) on node 1
[    0.000000] NUMA: Initmem setup node 3 [mem 0x00000000-0xffffffffffffffff]
[    0.000000] NUMA: NODE_DATA [mem 0x17fbfe8f00-0x17fbfea9ff]
[    0.000000] NUMA: NODE_DATA(3) on node 1

if printing "NUMA: Initmem setup node 2 [mem 0x00000000-0x00000000]",
it will make the log consistent with others, and obvious it's a memory-less
node as memory range 0x00000000-0x00000000, what do you think?

Thanks
Hanjun

^ permalink raw reply

* [PATCH v2 1/6] ARM: at91: Documentation: add samx7 families
From: Alexandre Belloni @ 2016-10-20 12:13 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <ae042bfa-4e92-a3ac-386a-31aeb8798776@atmel.com>

On 20/10/2016 at 14:01:24 +0200, Nicolas Ferre wrote :
> Le 20/10/2016 ? 11:41, Alexandre Belloni a ?crit :
> > The Atmel sams70, samv70 and samv71 are Cortex-M7 based MCUs that can run
> > Linux (without MMU).
> > 
> > Signed-off-by: Alexandre Belloni <alexandre.belloni@free-electrons.com>
> > ---
> >  Documentation/arm/Atmel/README | 44 +++++++++++++++++++++++++++++++++++++++---
> >  1 file changed, 41 insertions(+), 3 deletions(-)
> > 
> > diff --git a/Documentation/arm/Atmel/README b/Documentation/arm/Atmel/README
> > index 6ca78f818dbf..e403697ee9fc 100644
> > --- a/Documentation/arm/Atmel/README
> > +++ b/Documentation/arm/Atmel/README
> > @@ -14,9 +14,9 @@ official Atmel product name. Anyway, files, directories, git trees,
> >  git branches/tags and email subject always contain this "at91" sub-string.
> >  
> >  
> > -AT91 SoCs
> 
> Nope: AT91 is our historical name within the Linux community, we will
> keep it.
> 

Well, this is explained just on the line before, I was thinking that was
enough but whatever, marketing stuff ;)

> > ----------
> > -Documentation and detailled datasheet for each product are available on
> > +SMART SoCs
> 
> And I'm not sure about the naming of the product line nowadays:
> Atmel | SMART MPUs?
> Microchip / Atmel | SMART MPUs?
> Microchip MPUs?
> 
> But SoC is definitively too generic and "SMART" not needed here: let's
> keep the MPUs/MCUs only difference for this document.
> 

So, AT91 MPUs and SMART MCUs ?
Or I can put everything under AT91 SoCs

> > +----------
> > +Documentation and detailed datasheet for each product are available on
> >  the Atmel website: http://www.atmel.com.
> >  
> >    Flavors:
> > @@ -101,6 +101,44 @@ the Atmel website: http://www.atmel.com.
> >          + Datasheet
> >            http://www.atmel.com/Images/Atmel-11267-32-bit-Cortex-A5-Microcontroller-SAMA5D2_Datasheet.pdf
> >  
> > +SMART MCUs
> > +----------
> > +    * ARM Cortex-M7 MCUs
> > +      - sams70 family
> > +        - sams70j19
> > +        - sams70j20
> > +        - sams70j21
> > +        - sams70n19
> > +        - sams70n20
> > +        - sams70n21
> > +        - sams70q19
> > +        - sams70q20
> > +        - sams70q21
> > +        + Datasheet
> > +          http://www.atmel.com/Images/Atmel-11242-32-bit-Cortex-M7-Microcontroller-SAM-S70Q-SAM-S70N-SAM-S70J_Datasheet.pdf
> > +
> > +      - samv70 family
> > +        - samv70j19
> > +        - samv70j20
> > +        - samv70n19
> > +        - samv70n20
> > +        - samv70q19
> > +        - samv70q20
> > +        + Datasheet
> > +          http://www.atmel.com/Images/Atmel-11297-32-bit-Cortex-M7-Microcontroller-SAM-V70Q-SAM-V70N-SAM-V70J_Datasheet.pdf
> > +
> > +      - samv71 family
> > +        - samv71j19
> > +        - samv71j20
> > +        - samv71j21
> > +        - samv71n19
> > +        - samv71n20
> > +        - samv71n21
> > +        - samv71q19
> > +        - samv71q20
> > +        - samv71q21
> > +        + Datasheet
> > +          http://www.atmel.com/Images/Atmel-44003-32-bit-Cortex-M7-Microcontroller-SAM-V71Q-SAM-V71N-SAM-V71J_Datasheet.pdf
> >  
> >  Linux kernel information
> >  ------------------------
> > 
> 
> 
> -- 
> Nicolas Ferre

-- 
Alexandre Belloni, Free Electrons
Embedded Linux and Kernel engineering
http://free-electrons.com

^ permalink raw reply

* [PATCH 1/2] arm64/numa: fix pcpu_cpu_distance() to get correct CPU proximity
From: Hanjun Guo @ 2016-10-20 12:05 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20161020104815.GC24914@arm.com>

On 2016/10/20 18:48, Will Deacon wrote:
> On Thu, Oct 20, 2016 at 11:52:55AM +0800, Hanjun Guo wrote:
>> From: Yisheng Xie <xieyisheng1@huawei.com>
>>
>> The pcpu_build_alloc_info() function group CPUs according to their
>> proximity, by call callback function @cpu_distance_fn from different
>> ARCHs.
>>
>> For arm64 the callback of @cpu_distance_fn is
>>     pcpu_cpu_distance(from, to)
>>         -> node_distance(from, to)
>> The @from and @to for function node_distance() should be nid.
>>
>> However, pcpu_cpu_distance() in arch/arm64/mm/numa.c just past the
>> cpu id for @from and @to.
>>
>> For this incorrect cpu proximity get from ARCH, it may cause each CPU
>> in one group and make group_cnt out of bound:
>>
>> 	setup_per_cpu_areas()
>> 		pcpu_embed_first_chunk()
>> 			pcpu_build_alloc_info()
>> in pcpu_build_alloc_info, since cpu_distance_fn will return
>> REMOTE_DISTANCE if we pass cpu ids (0,1,2...), so
>> cpu_distance_fn(cpu, tcpu) > LOCAL_DISTANCE will wrongly be ture.
>>
>> This may results in triggering the BUG_ON(unit != nr_units) later:
>>
>> [    0.000000] kernel BUG at mm/percpu.c:1916!
>> [    0.000000] Internal error: Oops - BUG: 0 [#1] PREEMPT SMP
>> [    0.000000] Modules linked in:
>> [    0.000000] CPU: 0 PID: 0 Comm: swapper Not tainted 4.9.0-rc1-00003-g14155ca-dirty #26
>> [    0.000000] Hardware name: Hisilicon Hi1616 Evaluation Board (DT)
>> [    0.000000] task: ffff000008d6e900 task.stack: ffff000008d60000
>> [    0.000000] PC is at pcpu_embed_first_chunk+0x420/0x704
>> [    0.000000] LR is at pcpu_embed_first_chunk+0x3bc/0x704
>> [    0.000000] pc : [<ffff000008c754f4>] lr : [<ffff000008c75490>] pstate: 800000c5
>> [    0.000000] sp : ffff000008d63eb0
>> [    0.000000] x29: ffff000008d63eb0 [    0.000000] x28: 0000000000000000
>> [    0.000000] x27: 0000000000000040 [    0.000000] x26: ffff8413fbfcef00
>> [    0.000000] x25: 0000000000000042 [    0.000000] x24: 0000000000000042
>> [    0.000000] x23: 0000000000001000 [    0.000000] x22: 0000000000000046
>> [    0.000000] x21: 0000000000000001 [    0.000000] x20: ffff000008cb3bc8
>> [    0.000000] x19: ffff8413fbfcf570 [    0.000000] x18: 0000000000000000
>> [    0.000000] x17: ffff000008e49ae0 [    0.000000] x16: 0000000000000003
>> [    0.000000] x15: 000000000000001e [    0.000000] x14: 0000000000000004
>> [    0.000000] x13: 0000000000000000 [    0.000000] x12: 000000000000006f
>> [    0.000000] x11: 00000413fbffff00 [    0.000000] x10: 0000000000000004
>> [    0.000000] x9 : 0000000000000000 [    0.000000] x8 : 0000000000000001
>> [    0.000000] x7 : ffff8413fbfcf63c [    0.000000] x6 : ffff000008d65d28
>> [    0.000000] x5 : ffff000008d65e50 [    0.000000] x4 : 0000000000000000
>> [    0.000000] x3 : ffff000008cb3cc8 [    0.000000] x2 : 0000000000000040
>> [    0.000000] x1 : 0000000000000040 [    0.000000] x0 : 0000000000000000
>> [...]
>> [    0.000000] Call trace:
>> [    0.000000] Exception stack(0xffff000008d63ce0 to 0xffff000008d63e10)
>> [    0.000000] 3ce0: ffff8413fbfcf570 0001000000000000 ffff000008d63eb0 ffff000008c754f4
>> [    0.000000] 3d00: ffff000008d63d50 ffff0000081af210 00000413fbfff010 0000000000001000
>> [    0.000000] 3d20: ffff000008d63d50 ffff0000081af220 00000413fbfff010 0000000000001000
>> [    0.000000] 3d40: 00000413fbfcef00 0000000000000004 ffff000008d63db0 ffff0000081af390
>> [    0.000000] 3d60: 00000413fbfcef00 0000000000001000 0000000000000000 0000000000001000
>> [    0.000000] 3d80: 0000000000000000 0000000000000040 0000000000000040 ffff000008cb3cc8
>> [    0.000000] 3da0: 0000000000000000 ffff000008d65e50 ffff000008d65d28 ffff8413fbfcf63c
>> [    0.000000] 3dc0: 0000000000000001 0000000000000000 0000000000000004 00000413fbffff00
>> [    0.000000] 3de0: 000000000000006f 0000000000000000 0000000000000004 000000000000001e
>> [    0.000000] 3e00: 0000000000000003 ffff000008e49ae0
>> [    0.000000] [<ffff000008c754f4>] pcpu_embed_first_chunk+0x420/0x704
>> [    0.000000] [<ffff000008c6658c>] setup_per_cpu_areas+0x38/0xc8
>> [    0.000000] [<ffff000008c608d8>] start_kernel+0x10c/0x390
>> [    0.000000] [<ffff000008c601d8>] __primary_switched+0x5c/0x64
>> [    0.000000] Code: b8018660 17ffffd7 6b16037f 54000080 (d4210000)
>> [    0.000000] ---[ end trace 0000000000000000 ]---
>> [    0.000000] Kernel panic - not syncing: Attempted to kill the idle task!
>>
>> Fix by getting CPUs proximity through its node. We only care about
>> whether it is LOCAL_DISTANCE or not, for pcpu_build_alloc_info() only
>> use this to group CPUs.
>>
>> Fixes: 7af3a0a99252 ("arm64/numa: support HAVE_SETUP_PER_CPU_AREA")
>> Signed-off-by: Yisheng Xie <xieyisheng1@huawei.com>
>> Signed-off-by: Hanjun Guo <hanjun.guo@linaro.org>
>> Cc: Catalin Marinas <catalin.marinas@arm.com>
>> Cc: Lorenzo Pieralisi <lorenzo.pieralisi@arm.com>
>> Cc: Will Deacon <will.deacon@arm.com>
>> Cc: Zhen Lei <thunder.leizhen@huawei.com>
>> ---
>>  arch/arm64/mm/numa.c | 5 ++++-
>>  1 file changed, 4 insertions(+), 1 deletion(-)
>>
>> diff --git a/arch/arm64/mm/numa.c b/arch/arm64/mm/numa.c
>> index 778a985..34415fc 100644
>> --- a/arch/arm64/mm/numa.c
>> +++ b/arch/arm64/mm/numa.c
>> @@ -147,7 +147,10 @@ static int __init early_cpu_to_node(int cpu)
>>  
>>  static int __init pcpu_cpu_distance(unsigned int from, unsigned int to)
>>  {
>> -	return node_distance(from, to);
>> +	if (early_cpu_to_node(from) == early_cpu_to_node(to))
>> +		return LOCAL_DISTANCE;
>> +	else
>> +		return REMOTE_DISTANCE;
> Why can't this be node_distance(early_cpu_to_node(from), early_cpu_to_node(to))?

It's really some coding style preference and the caller function is only care about
it's LOCAL_DISTANCE or not, as we said in the commit message.

But using node_distance() will save few lines of code and no functional change,
will update it.

Thanks
Hanjun

^ permalink raw reply

* [PATCH v2 1/6] ARM: at91: Documentation: add samx7 families
From: Nicolas Ferre @ 2016-10-20 12:01 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20161020094135.18221-2-alexandre.belloni@free-electrons.com>

Le 20/10/2016 ? 11:41, Alexandre Belloni a ?crit :
> The Atmel sams70, samv70 and samv71 are Cortex-M7 based MCUs that can run
> Linux (without MMU).
> 
> Signed-off-by: Alexandre Belloni <alexandre.belloni@free-electrons.com>
> ---
>  Documentation/arm/Atmel/README | 44 +++++++++++++++++++++++++++++++++++++++---
>  1 file changed, 41 insertions(+), 3 deletions(-)
> 
> diff --git a/Documentation/arm/Atmel/README b/Documentation/arm/Atmel/README
> index 6ca78f818dbf..e403697ee9fc 100644
> --- a/Documentation/arm/Atmel/README
> +++ b/Documentation/arm/Atmel/README
> @@ -14,9 +14,9 @@ official Atmel product name. Anyway, files, directories, git trees,
>  git branches/tags and email subject always contain this "at91" sub-string.
>  
>  
> -AT91 SoCs

Nope: AT91 is our historical name within the Linux community, we will
keep it.

> ----------
> -Documentation and detailled datasheet for each product are available on
> +SMART SoCs

And I'm not sure about the naming of the product line nowadays:
Atmel | SMART MPUs?
Microchip / Atmel | SMART MPUs?
Microchip MPUs?

But SoC is definitively too generic and "SMART" not needed here: let's
keep the MPUs/MCUs only difference for this document.

> +----------
> +Documentation and detailed datasheet for each product are available on
>  the Atmel website: http://www.atmel.com.
>  
>    Flavors:
> @@ -101,6 +101,44 @@ the Atmel website: http://www.atmel.com.
>          + Datasheet
>            http://www.atmel.com/Images/Atmel-11267-32-bit-Cortex-A5-Microcontroller-SAMA5D2_Datasheet.pdf
>  
> +SMART MCUs
> +----------
> +    * ARM Cortex-M7 MCUs
> +      - sams70 family
> +        - sams70j19
> +        - sams70j20
> +        - sams70j21
> +        - sams70n19
> +        - sams70n20
> +        - sams70n21
> +        - sams70q19
> +        - sams70q20
> +        - sams70q21
> +        + Datasheet
> +          http://www.atmel.com/Images/Atmel-11242-32-bit-Cortex-M7-Microcontroller-SAM-S70Q-SAM-S70N-SAM-S70J_Datasheet.pdf
> +
> +      - samv70 family
> +        - samv70j19
> +        - samv70j20
> +        - samv70n19
> +        - samv70n20
> +        - samv70q19
> +        - samv70q20
> +        + Datasheet
> +          http://www.atmel.com/Images/Atmel-11297-32-bit-Cortex-M7-Microcontroller-SAM-V70Q-SAM-V70N-SAM-V70J_Datasheet.pdf
> +
> +      - samv71 family
> +        - samv71j19
> +        - samv71j20
> +        - samv71j21
> +        - samv71n19
> +        - samv71n20
> +        - samv71n21
> +        - samv71q19
> +        - samv71q20
> +        - samv71q21
> +        + Datasheet
> +          http://www.atmel.com/Images/Atmel-44003-32-bit-Cortex-M7-Microcontroller-SAM-V71Q-SAM-V71N-SAM-V71J_Datasheet.pdf
>  
>  Linux kernel information
>  ------------------------
> 


-- 
Nicolas Ferre

^ permalink raw reply

* [PATCH] pinctrl: st: don't specify default interrupt trigger
From: Peter Griffin @ 2016-10-20 11:56 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <729ebc94-5476-65a7-cc17-eabfba0d2404@st.com>

Hi Patrice,

On Thu, 20 Oct 2016, Patrice Chotard wrote:

> 
> 
> On 10/18/2016 09:16 AM, patrice.chotard at st.com wrote:
> > From: Patrice Chotard <patrice.chotard@st.com>
> > 
> > Thanks to 332e99d5ae4 which now alerts of default
> > trigger usage when configuring interrupts.
> > 
> > Signed-off-by: Patrice Chotard <patrice.chotard@st.com>
> > ---
> >  drivers/pinctrl/pinctrl-st.c | 2 +-
> >  1 file changed, 1 insertion(+), 1 deletion(-)
> > 
> > diff --git a/drivers/pinctrl/pinctrl-st.c b/drivers/pinctrl/pinctrl-st.c
> > index 99da4cf..b7bb371 100644
> > --- a/drivers/pinctrl/pinctrl-st.c
> > +++ b/drivers/pinctrl/pinctrl-st.c
> > @@ -1512,7 +1512,7 @@ static int st_gpiolib_register_bank(struct st_pinctrl *info,
> >  	if (info->irqmux_base || gpio_irq > 0) {
> >  		err = gpiochip_irqchip_add(&bank->gpio_chip, &st_gpio_irqchip,
> >  					   0, handle_simple_irq,
> > -					   IRQ_TYPE_LEVEL_LOW);
> > +					   IRQ_TYPE_NONE);
> >  		if (err) {
> >  			gpiochip_remove(&bank->gpio_chip);
> >  			dev_info(dev, "could not add irqchip\n");
> > 
> 
> Hi Linus
> 
> I forgot to mention that this patch is dedicated for v4.9-rcs 

Wow, v4.9-rc is a noisy boot without this patch :)

Acked-by: Peter Griffin <peter.griffin@linaro.org>

^ permalink raw reply

* [PATCH 6/8] pinctrl: aspeed-g4: Capture SuperIO pinmux dependency
From: Linus Walleij @ 2016-10-20 11:53 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <b5f67ba76018314d08e240f95951751896687d37.1474986045.git-series.andrew@aj.id.au>

On Tue, Sep 27, 2016 at 4:50 PM, Andrew Jeffery <andrew@aj.id.au> wrote:

> Two LPC-related signals in the AST2400 depend on state in the SuperIO IP
> block. Use the recently added infrastructure to capture this
> relationship.
>
> Signed-off-by: Andrew Jeffery <andrew@aj.id.au>

Patch applied for v4.10.
(Tell me if I'm applying patches in wrong order or something, and
I hope this doesn't clash with the fixes.)

Yours,
Linus Walleij

^ permalink raw reply

* [PATCH] ARM64: defconfig: Enable MMC related configs
From: Neil Armstrong @ 2016-10-20 11:49 UTC (permalink / raw)
  To: linux-arm-kernel

Enable MMC related defaults configs for MMC, PWM and PWM clock.

Signed-off-by: Neil Armstrong <narmstrong@baylibre.com>
---
 arch/arm64/configs/defconfig | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/arch/arm64/configs/defconfig b/arch/arm64/configs/defconfig
index dab2cb0..920f1e8 100644
--- a/arch/arm64/configs/defconfig
+++ b/arch/arm64/configs/defconfig
@@ -341,6 +341,7 @@ CONFIG_USB_RENESAS_USBHS_UDC=m
 CONFIG_MMC=y
 CONFIG_MMC_BLOCK_MINORS=32
 CONFIG_MMC_ARMMMCI=y
+CONFIG_MMC_MESON_GX=y
 CONFIG_MMC_SDHCI=y
 CONFIG_MMC_SDHCI_ACPI=y
 CONFIG_MMC_SDHCI_PLTFM=y
@@ -387,6 +388,7 @@ CONFIG_XEN_GRANT_DEV_ALLOC=y
 CONFIG_COMMON_CLK_SCPI=y
 CONFIG_COMMON_CLK_CS2000_CP=y
 CONFIG_COMMON_CLK_S2MPS11=y
+CONFIG_COMMON_CLK_PWM=y
 CONFIG_CLK_QORIQ=y
 CONFIG_COMMON_CLK_QCOM=y
 CONFIG_MSM_GCC_8916=y
@@ -404,6 +406,7 @@ CONFIG_ARCH_TEGRA_210_SOC=y
 CONFIG_EXTCON_USB_GPIO=y
 CONFIG_PWM=y
 CONFIG_PWM_TEGRA=m
+CONFIG_PWM_MESON=m
 CONFIG_COMMON_RESET_HI6220=y
 CONFIG_PHY_RCAR_GEN3_USB2=y
 CONFIG_PHY_HI6220_USB=y
-- 
1.9.1

^ permalink raw reply related

* [PATCH 4/4] ARM64: dts: meson-gxbb: Add MMC nodes to Nexbox A95x
From: Neil Armstrong @ 2016-10-20 11:42 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1476963777-1804-1-git-send-email-narmstrong@baylibre.com>

Add support for eMMC/SD/SDIO on the Nexbox A95x.

Signed-off-by: Neil Armstrong <narmstrong@baylibre.com>
---
 .../boot/dts/amlogic/meson-gxbb-nexbox-a95x.dts    | 122 +++++++++++++++++++++
 1 file changed, 122 insertions(+)

diff --git a/arch/arm64/boot/dts/amlogic/meson-gxbb-nexbox-a95x.dts b/arch/arm64/boot/dts/amlogic/meson-gxbb-nexbox-a95x.dts
index 399d85f..9696820 100644
--- a/arch/arm64/boot/dts/amlogic/meson-gxbb-nexbox-a95x.dts
+++ b/arch/arm64/boot/dts/amlogic/meson-gxbb-nexbox-a95x.dts
@@ -87,6 +87,61 @@
 			gpios = <&gpio_ao GPIOAO_3 GPIO_ACTIVE_LOW>;
 		};
 	};
+
+	vddio_card: gpio-regulator {
+		compatible = "regulator-gpio";
+
+		regulator-name = "VDDIO_CARD";
+		regulator-min-microvolt = <1800000>;
+		regulator-max-microvolt = <3300000>;
+
+		gpios = <&gpio_ao GPIOAO_5 GPIO_ACTIVE_HIGH>;
+		gpios-states = <1>;
+
+		/* Based on P200 schematics, signal CARD_1.8V/3.3V_CTR */
+		states = <1800000 0
+			  3300000 1>;
+	};
+
+	vddio_boot: regulator-vddio_boot {
+		compatible = "regulator-fixed";
+		regulator-name = "VDDIO_BOOT";
+		regulator-min-microvolt = <1800000>;
+		regulator-max-microvolt = <1800000>;
+	};
+
+	vddao_3v3: regulator-vddao_3v3 {
+		compatible = "regulator-fixed";
+		regulator-name = "VDDAO_3V3";
+		regulator-min-microvolt = <3300000>;
+		regulator-max-microvolt = <3300000>;
+	};
+
+	vcc_3v3: regulator-vcc_3v3 {
+		compatible = "regulator-fixed";
+		regulator-name = "VCC_3V3";
+		regulator-min-microvolt = <3300000>;
+		regulator-max-microvolt = <3300000>;
+	};
+
+	emmc_pwrseq: emmc-pwrseq {
+		compatible = "mmc-pwrseq-emmc";
+		reset-gpios = <&gpio BOOT_9 GPIO_ACTIVE_LOW>;
+	};
+
+	wifi32k: wifi32k {
+		compatible = "pwm-clock";
+		#clock-cells = <0>;
+		clock-frequency = <32768>;
+		pwms = <&pwm_ef 0 30518 0>; /* PWM_E at 32.768KHz */
+	};
+
+	sdio_pwrseq: sdio-pwrseq {
+		compatible = "mmc-pwrseq-simple";
+		reset-gpios = <&gpio GPIOX_6 GPIO_ACTIVE_LOW>;
+		clocks = <&wifi32k>;
+		clock-names = "ext_clock";
+	};
 };
 
 &uart_AO {
@@ -107,3 +162,70 @@
 	pinctrl-0 = <&remote_input_ao_pins>;
 	pinctrl-names = "default";
 };
+
+/* Wireless SDIO Module */
+&sd_emmc_a {
+	status = "okay";
+	pinctrl-0 = <&sdio_pins>;
+	pinctrl-names = "default";
+	#address-cells = <1>;
+	#size-cells = <0>;
+
+	bus-width = <4>;
+	cap-sd-highspeed;
+	max-frequency = <100000000>;
+
+	non-removable;
+	disable-wp;
+
+	mmc-pwrseq = <&sdio_pwrseq>;
+
+	vmmc-supply = <&vddao_3v3>;
+	vqmmc-supply = <&vddio_boot>;
+};
+
+/* SD card */
+&sd_emmc_b {
+	status = "okay";
+	pinctrl-0 = <&sdcard_pins>;
+	pinctrl-names = "default";
+
+	bus-width = <4>;
+	cap-sd-highspeed;
+	max-frequency = <100000000>;
+	disable-wp;
+
+	cd-gpios = <&gpio CARD_6 GPIO_ACTIVE_HIGH>;
+	cd-inverted;
+
+	vmmc-supply = <&vddao_3v3>;
+	vqmmc-supply = <&vddio_card>;
+};
+
+/* eMMC */
+&sd_emmc_c {
+	status = "okay";
+	pinctrl-0 = <&emmc_pins>;
+	pinctrl-names = "default";
+
+	bus-width = <8>;
+	cap-sd-highspeed;
+	cap-mmc-highspeed;
+	max-frequency = <200000000>;
+	non-removable;
+	disable-wp;
+	mmc-ddr-1_8v;
+	mmc-hs200-1_8v;
+
+	mmc-pwrseq = <&emmc_pwrseq>;
+	vmmc-supply = <&vcc_3v3>;
+	vqmmc-supply = <&vddio_boot>;
+};
+
+&pwm_ef {
+	status = "okay";
+	pinctrl-0 = <&pwm_e_pins>;
+	pinctrl-names = "default";
+	clocks = <&clkc CLKID_FCLK_DIV4>;
+	clock-names = "clkin0";
+};
-- 
1.9.1

^ permalink raw reply related

* [PATCH 3/4] ARM64: dts: meson-gxbb: Add P20x Wifi SDIO support
From: Neil Armstrong @ 2016-10-20 11:42 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1476963777-1804-1-git-send-email-narmstrong@baylibre.com>

Add Wifi module support on the Amlogic P20x boards on the SDIO port.
The Wifi module also needs a 32768Hz clock provided by the PWM E port
through a pwm-clock node in it's power sequence.

Signed-off-by: Neil Armstrong <narmstrong@baylibre.com>
---
 arch/arm64/boot/dts/amlogic/meson-gxbb-p20x.dtsi | 14 ++++++++++++++
 1 file changed, 14 insertions(+)

diff --git a/arch/arm64/boot/dts/amlogic/meson-gxbb-p20x.dtsi b/arch/arm64/boot/dts/amlogic/meson-gxbb-p20x.dtsi
index 6861b0a..203be28 100644
--- a/arch/arm64/boot/dts/amlogic/meson-gxbb-p20x.dtsi
+++ b/arch/arm64/boot/dts/amlogic/meson-gxbb-p20x.dtsi
@@ -118,6 +118,13 @@
 		clock-frequency = <32768>;
 		pwms = <&pwm_ef 0 30518 0>; /* PWM_E at 32.768KHz */
 	};
+
+	sdio_pwrseq: sdio-pwrseq {
+		compatible = "mmc-pwrseq-simple";
+		reset-gpios = <&gpio GPIOX_6 GPIO_ACTIVE_LOW>;
+		clocks = <&wifi32k>;
+		clock-names = "ext_clock";
+	};
 };
 
 /* This UART is brought out to the DB9 connector */
@@ -171,8 +178,15 @@
 	non-removable;
 	disable-wp;
 
+	mmc-pwrseq = <&sdio_pwrseq>;
+
 	vmmc-supply = <&vddao_3v3>;
 	vqmmc-supply = <&vddio_boot>;
+
+	brcmf: bcrmf at 1 {
+		reg = <1>;
+		compatible = "brcm,bcm4329-fmac";
+	};
 };
 
 /* SD card */
-- 
1.9.1

^ permalink raw reply related

* [PATCH 2/4] ARM64: dts: meson-gxbb: Add Wifi 32K clock for p20x boards
From: Neil Armstrong @ 2016-10-20 11:42 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1476963777-1804-1-git-send-email-narmstrong@baylibre.com>

Add a 32768Hz clock generated by the PWM E port used by the WiFi module.

Signed-off-by: Neil Armstrong <narmstrong@baylibre.com>
---
 arch/arm64/boot/dts/amlogic/meson-gxbb-p20x.dtsi | 15 +++++++++++++++
 1 file changed, 15 insertions(+)

diff --git a/arch/arm64/boot/dts/amlogic/meson-gxbb-p20x.dtsi b/arch/arm64/boot/dts/amlogic/meson-gxbb-p20x.dtsi
index 86e740f..6861b0a 100644
--- a/arch/arm64/boot/dts/amlogic/meson-gxbb-p20x.dtsi
+++ b/arch/arm64/boot/dts/amlogic/meson-gxbb-p20x.dtsi
@@ -111,6 +111,13 @@
 		compatible = "mmc-pwrseq-emmc";
 		reset-gpios = <&gpio BOOT_9 GPIO_ACTIVE_LOW>;
 	};
+
+	wifi32k: wifi32k {
+		compatible = "pwm-clock";
+		#clock-cells = <0>;
+		clock-frequency = <32768>;
+		pwms = <&pwm_ef 0 30518 0>; /* PWM_E at 32.768KHz */
+	};
 };
 
 /* This UART is brought out to the DB9 connector */
@@ -205,3 +212,11 @@
 	vmmc-supply = <&vcc_3v3>;
 	vqmmc-supply = <&vddio_boot>;
 };
+
+&pwm_ef {
+	status = "okay";
+	pinctrl-0 = <&pwm_e_pins>;
+	pinctrl-names = "default";
+	clocks = <&clkc CLKID_FCLK_DIV4>;
+	clock-names = "clkin0";
+};
-- 
1.9.1

^ permalink raw reply related

* [PATCH 1/4] ARM64: dts: meson-gxbb: add MMC support
From: Neil Armstrong @ 2016-10-20 11:42 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1476963777-1804-1-git-send-email-narmstrong@baylibre.com>

From: Kevin Hilman <khilman@baylibre.com>

Add binding and basic support for the SD/eMMC controller on Amlogic
S905/GXBB devices.

Acked-by: Rob Herring <robh@kernel.org>
Signed-off-by: Kevin Hilman <khilman@baylibre.com>
Signed-off-by: Neil Armstrong <narmstrong@baylibre.com>
---
 arch/arm64/boot/dts/amlogic/meson-gx.dtsi          | 21 +++++
 .../arm64/boot/dts/amlogic/meson-gxbb-odroidc2.dts | 88 +++++++++++++++++++
 arch/arm64/boot/dts/amlogic/meson-gxbb-p20x.dtsi   | 98 ++++++++++++++++++++++
 arch/arm64/boot/dts/amlogic/meson-gxbb.dtsi        | 24 +++++-
 4 files changed, 230 insertions(+), 1 deletion(-)

diff --git a/arch/arm64/boot/dts/amlogic/meson-gx.dtsi b/arch/arm64/boot/dts/amlogic/meson-gx.dtsi
index a6cd953..fd1d0de 100644
--- a/arch/arm64/boot/dts/amlogic/meson-gx.dtsi
+++ b/arch/arm64/boot/dts/amlogic/meson-gx.dtsi
@@ -203,6 +203,27 @@
 			#address-cells = <2>;
 			#size-cells = <2>;
 			ranges = <0x0 0x0 0x0 0xd0000000 0x0 0x200000>;
+
+			sd_emmc_a: mmc at 70000 {
+				compatible = "amlogic,meson-gx-mmc", "amlogic,meson-gxbb-mmc";
+				reg = <0x0 0x70000 0x0 0x2000>;
+				interrupts = <GIC_SPI 216 IRQ_TYPE_EDGE_RISING>;
+				status = "disabled";
+			};
+
+			sd_emmc_b: mmc at 72000 {
+				compatible = "amlogic,meson-gx-mmc", "amlogic,meson-gxbb-mmc";
+				reg = <0x0 0x72000 0x0 0x2000>;
+				interrupts = <GIC_SPI 217 IRQ_TYPE_EDGE_RISING>;
+				status = "disabled";
+			};
+
+			sd_emmc_c: mmc at 74000 {
+				compatible = "amlogic,meson-gx-mmc", "amlogic,meson-gxbb-mmc";
+				reg = <0x0 0x74000 0x0 0x2000>;
+				interrupts = <GIC_SPI 218 IRQ_TYPE_EDGE_RISING>;
+				status = "disabled";
+			};
 		};
 	};
 };
diff --git a/arch/arm64/boot/dts/amlogic/meson-gxbb-odroidc2.dts b/arch/arm64/boot/dts/amlogic/meson-gxbb-odroidc2.dts
index a45d101..238fbea 100644
--- a/arch/arm64/boot/dts/amlogic/meson-gxbb-odroidc2.dts
+++ b/arch/arm64/boot/dts/amlogic/meson-gxbb-odroidc2.dts
@@ -85,6 +85,56 @@
 			default-state = "off";
 		};
 	};
+
+	tflash_vdd: regulator-tflash_vdd {
+		/*
+		 * signal name from schematics: TFLASH_VDD_EN
+		 */
+		compatible = "regulator-fixed";
+
+		regulator-name = "TFLASH_VDD";
+		regulator-min-microvolt = <3300000>;
+		regulator-max-microvolt = <3300000>;
+
+		gpio = <&gpio_ao GPIOAO_12 GPIO_ACTIVE_HIGH>;
+		enable-active-high;
+	};
+
+	tf_io: gpio-regulator-tf_io {
+		compatible = "regulator-gpio";
+
+		regulator-name = "TF_IO";
+		regulator-min-microvolt = <1800000>;
+		regulator-max-microvolt = <3300000>;
+
+		/*
+		 * signal name from schematics: TF_3V3N_1V8_EN
+		 */
+		gpios = <&gpio_ao GPIOAO_3 GPIO_ACTIVE_HIGH>;
+		gpios-states = <0>;
+
+		states = <3300000 0
+			  1800000 1>;
+	};
+
+	vcc1v8: regulator-vcc1v8 {
+		compatible = "regulator-fixed";
+		regulator-name = "VCC1V8";
+		regulator-min-microvolt = <1800000>;
+		regulator-max-microvolt = <1800000>;
+	};
+
+	vcc3v3: regulator-vcc3v3 {
+		compatible = "regulator-fixed";
+		regulator-name = "VCC3V3";
+		regulator-min-microvolt = <3300000>;
+		regulator-max-microvolt = <3300000>;
+	};
+
+	emmc_pwrseq: emmc-pwrseq {
+		compatible = "mmc-pwrseq-emmc";
+		reset-gpios = <&gpio BOOT_9 GPIO_ACTIVE_LOW>;
+	};
 };
 
 &uart_AO {
@@ -127,3 +177,41 @@
 &usb1 {
 	status = "okay";
 };
+
+/* SD */
+&sd_emmc_b {
+	status = "okay";
+	pinctrl-0 = <&sdcard_pins>;
+	pinctrl-names = "default";
+
+	bus-width = <4>;
+	cap-sd-highspeed;
+	max-frequency = <100000000>;
+	disable-wp;
+
+	cd-gpios = <&gpio CARD_6 GPIO_ACTIVE_HIGH>;
+	cd-inverted;
+
+	vmmc-supply = <&tflash_vdd>;
+	vqmmc-supply = <&tf_io>;
+};
+
+/* eMMC */
+&sd_emmc_c {
+	status = "okay";
+	pinctrl-0 = <&emmc_pins>;
+	pinctrl-names = "default";
+
+	bus-width = <8>;
+	cap-sd-highspeed;
+	max-frequency = <200000000>;
+	non-removable;
+	disable-wp;
+	cap-mmc-highspeed;
+	mmc-ddr-1_8v;
+	mmc-hs200-1_8v;
+
+	mmc-pwrseq = <&emmc_pwrseq>;
+	vmmc-supply = <&vcc3v3>;
+	vqmmc-supply = <&vcc1v8>;
+};
diff --git a/arch/arm64/boot/dts/amlogic/meson-gxbb-p20x.dtsi b/arch/arm64/boot/dts/amlogic/meson-gxbb-p20x.dtsi
index 031d69b..86e740f 100644
--- a/arch/arm64/boot/dts/amlogic/meson-gxbb-p20x.dtsi
+++ b/arch/arm64/boot/dts/amlogic/meson-gxbb-p20x.dtsi
@@ -70,6 +70,47 @@
 		gpio = <&gpio GPIODV_24 GPIO_ACTIVE_HIGH>;
 		enable-active-high;
 	};
+
+	vddio_card: gpio-regulator {
+		compatible = "regulator-gpio";
+
+		regulator-name = "VDDIO_CARD";
+		regulator-min-microvolt = <1800000>;
+		regulator-max-microvolt = <3300000>;
+
+		gpios = <&gpio_ao GPIOAO_5 GPIO_ACTIVE_HIGH>;
+		gpios-states = <1>;
+
+		/* Based on P200 schematics, signal CARD_1.8V/3.3V_CTR */
+		states = <1800000 0
+			  3300000 1>;
+	};
+
+	vddio_boot: regulator-vddio_boot {
+		compatible = "regulator-fixed";
+		regulator-name = "VDDIO_BOOT";
+		regulator-min-microvolt = <1800000>;
+		regulator-max-microvolt = <1800000>;
+	};
+
+	vddao_3v3: regulator-vddao_3v3 {
+		compatible = "regulator-fixed";
+		regulator-name = "VDDAO_3V3";
+		regulator-min-microvolt = <3300000>;
+		regulator-max-microvolt = <3300000>;
+	};
+
+	vcc_3v3: regulator-vcc_3v3 {
+		compatible = "regulator-fixed";
+		regulator-name = "VCC_3V3";
+		regulator-min-microvolt = <3300000>;
+		regulator-max-microvolt = <3300000>;
+	};
+
+	emmc_pwrseq: emmc-pwrseq {
+		compatible = "mmc-pwrseq-emmc";
+		reset-gpios = <&gpio BOOT_9 GPIO_ACTIVE_LOW>;
+	};
 };
 
 /* This UART is brought out to the DB9 connector */
@@ -107,3 +148,60 @@
 &usb1 {
 	status = "okay";
 };
+
+/* Wireless SDIO Module */
+&sd_emmc_a {
+	status = "okay";
+	pinctrl-0 = <&sdio_pins>;
+	pinctrl-names = "default";
+	#address-cells = <1>;
+	#size-cells = <0>;
+
+	bus-width = <4>;
+	cap-sd-highspeed;
+	max-frequency = <100000000>;
+
+	non-removable;
+	disable-wp;
+
+	vmmc-supply = <&vddao_3v3>;
+	vqmmc-supply = <&vddio_boot>;
+};
+
+/* SD card */
+&sd_emmc_b {
+	status = "okay";
+	pinctrl-0 = <&sdcard_pins>;
+	pinctrl-names = "default";
+
+	bus-width = <4>;
+	cap-sd-highspeed;
+	max-frequency = <100000000>;
+	disable-wp;
+
+	cd-gpios = <&gpio CARD_6 GPIO_ACTIVE_HIGH>;
+	cd-inverted;
+
+	vmmc-supply = <&vddao_3v3>;
+	vqmmc-supply = <&vddio_card>;
+};
+
+/* eMMC */
+&sd_emmc_c {
+	status = "okay";
+	pinctrl-0 = <&emmc_pins>;
+	pinctrl-names = "default";
+
+	bus-width = <8>;
+	cap-sd-highspeed;
+	cap-mmc-highspeed;
+	max-frequency = <200000000>;
+	non-removable;
+	disable-wp;
+	mmc-ddr-1_8v;
+	mmc-hs200-1_8v;
+
+	mmc-pwrseq = <&emmc_pwrseq>;
+	vmmc-supply = <&vcc_3v3>;
+	vqmmc-supply = <&vddio_boot>;
+};
diff --git a/arch/arm64/boot/dts/amlogic/meson-gxbb.dtsi b/arch/arm64/boot/dts/amlogic/meson-gxbb.dtsi
index aad639a..22940bb 100644
--- a/arch/arm64/boot/dts/amlogic/meson-gxbb.dtsi
+++ b/arch/arm64/boot/dts/amlogic/meson-gxbb.dtsi
@@ -349,7 +349,8 @@
 			mux {
 				groups = "emmc_nand_d07",
 				       "emmc_cmd",
-				       "emmc_clk";
+				       "emmc_clk",
+				       "emmc_ds";
 				function = "emmc";
 			};
 		};
@@ -545,3 +546,24 @@
 		#mbox-cells = <1>;
 	};
 };
+
+&sd_emmc_a {
+	clocks = <&clkc CLKID_SD_EMMC_A>,
+		 <&xtal>,
+		 <&clkc CLKID_FCLK_DIV2>;
+	clock-names = "core", "clkin0", "clkin1";
+};
+
+&sd_emmc_b {
+	clocks = <&clkc CLKID_SD_EMMC_B>,
+		 <&xtal>,
+		 <&clkc CLKID_FCLK_DIV2>;
+	clock-names = "core", "clkin0", "clkin1";
+};
+
+&sd_emmc_c {
+	clocks = <&clkc CLKID_SD_EMMC_C>,
+		 <&xtal>,
+		 <&clkc CLKID_FCLK_DIV2>;
+	clock-names = "core", "clkin0", "clkin1";
+};
-- 
1.9.1

^ permalink raw reply related


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