All of lore.kernel.org
 help / color / mirror / Atom feed
From: Icenowy Zheng <icenowy@aosc.io>
To: Maxime Ripard <maxime.ripard@free-electrons.com>
Cc: devicetree@vger.kernel.org,
	Jernej Skrabec <jernej.skrabec@siol.net>,
	David Airlie <airlied@linux.ie>,
	linux-sunxi@googlegroups.com, linux-kernel@vger.kernel.org,
	dri-devel@lists.freedesktop.org, Chen-Yu Tsai <wens@csie.org>,
	Rob Herring <robh+dt@kernel.org>,
	linux-clk@vger.kernel.org, linux-arm-kernel@lists.infradead.org
Subject: Re: [PATCH v4 06/11] drm/sun4i: add support for Allwinner DE2 mixers
Date: Tue, 18 Apr 2017 18:47:56 +0800	[thread overview]
Message-ID: <88F5FAC9-1873-4C76-9AB9-FF361C07664E@aosc.io> (raw)
In-Reply-To: <20170418090047.7i2k6dtoqxfdqwwy@lukather>



于 2017年4月18日 GMT+08:00 下午5:00:47, Maxime Ripard <maxime.ripard@free-electrons.com> 写到:
>On Sun, Apr 16, 2017 at 08:08:44PM +0800, Icenowy Zheng wrote:
>> Allwinner have a new "Display Engine 2.0" in their new SoCs, which
>comes
>> with mixers to do graphic processing and feed data to TCON, like the
>old
>> backends and frontends.
>> 
>> Add support for the mixer on Allwinner V3s SoC; it's the simplest
>one.
>> 
>> Currently a lot of functions are still missing -- more investigations
>> are needed to gain enough information for them.
>> 
>> Signed-off-by: Icenowy Zheng <icenowy@aosc.io>
>> ---
>> Changes in v4:
>> - Killed some dead code according to Jernej.
>> 
>>  drivers/gpu/drm/sun4i/Kconfig       |  10 +
>>  drivers/gpu/drm/sun4i/Makefile      |   4 +
>>  drivers/gpu/drm/sun4i/sun8i_layer.c | 142 ++++++++++++++
>>  drivers/gpu/drm/sun4i/sun8i_layer.h |  36 ++++
>>  drivers/gpu/drm/sun4i/sun8i_mixer.c | 381
>++++++++++++++++++++++++++++++++++++
>>  drivers/gpu/drm/sun4i/sun8i_mixer.h | 131 +++++++++++++
>>  6 files changed, 704 insertions(+)
>>  create mode 100644 drivers/gpu/drm/sun4i/sun8i_layer.c
>>  create mode 100644 drivers/gpu/drm/sun4i/sun8i_layer.h
>>  create mode 100644 drivers/gpu/drm/sun4i/sun8i_mixer.c
>>  create mode 100644 drivers/gpu/drm/sun4i/sun8i_mixer.h
>> 
>> diff --git a/drivers/gpu/drm/sun4i/Kconfig
>b/drivers/gpu/drm/sun4i/Kconfig
>> index 5a8227f37cc4..15557484520d 100644
>> --- a/drivers/gpu/drm/sun4i/Kconfig
>> +++ b/drivers/gpu/drm/sun4i/Kconfig
>> @@ -22,3 +22,13 @@ config DRM_SUN4I_BACKEND
>>  	  original Allwinner Display Engine, which has a backend to
>>  	  do some alpha blending and feed graphics to TCON. If M is
>>  	  selected the module will be called sun4i-backend.
>> +
>> +config DRM_SUN4I_SUN8I_MIXER
>> +	tristate "Support for Allwinner Display Engine 2.0 Mixer"
>> +	depends on DRM_SUN4I
>> +	default MACH_SUN8I
>> +	help
>> +	  Choose this option if you have an Allwinner SoC with the
>> +	  Allwinner Display Engine 2.0, which has a mixer to do some
>> +	  graphics mixture and feed graphics to TCON, If M is
>> +	  selected the module will be called sun8i-mixer.
>> diff --git a/drivers/gpu/drm/sun4i/Makefile
>b/drivers/gpu/drm/sun4i/Makefile
>> index 1db1068b9be1..7625c2dad1bb 100644
>> --- a/drivers/gpu/drm/sun4i/Makefile
>> +++ b/drivers/gpu/drm/sun4i/Makefile
>> @@ -9,7 +9,11 @@ sun4i-tcon-y += sun4i_crtc.o
>>  sun4i-backend-y += sun4i_layer.o
>>  sun4i-backend-y += sun4i_backend.o
>>  
>> +sun8i-mixer-y += sun8i_layer.o
>> +sun8i-mixer-y += sun8i_mixer.o
>> +
>>  obj-$(CONFIG_DRM_SUN4I)		+= sun4i-drm.o sun4i-tcon.o
>>  obj-$(CONFIG_DRM_SUN4I_BACKEND)	+= sun4i-backend.o
>> +obj-$(CONFIG_DRM_SUN4I_SUN8I_MIXER) += sun8i-mixer.o
>
>Please align the value using tabs.

Should I re-align existed items?

>
>>  obj-$(CONFIG_DRM_SUN4I)		+= sun6i_drc.o
>>  obj-$(CONFIG_DRM_SUN4I)		+= sun4i_tv.o
>> diff --git a/drivers/gpu/drm/sun4i/sun8i_layer.c
>b/drivers/gpu/drm/sun4i/sun8i_layer.c
>> new file mode 100644
>> index 000000000000..d70a90d963b0
>> --- /dev/null
>> +++ b/drivers/gpu/drm/sun4i/sun8i_layer.c
>> @@ -0,0 +1,142 @@
>> +/*
>> + * Copyright (C) Icenowy Zheng <icenowy@aosc.io>
>> + *
>> + * Based on sun4i_layer.h, which is:
>> + *   Copyright (C) 2015 Free Electrons
>> + *   Copyright (C) 2015 NextThing Co
>> + *
>> + *   Maxime Ripard <maxime.ripard@free-electrons.com>
>> + *
>> + * This program is free software; you can redistribute it and/or
>> + * modify it under the terms of the GNU General Public License as
>> + * published by the Free Software Foundation; either version 2 of
>> + * the License, or (at your option) any later version.
>> + */
>> +
>> +#include <drm/drm_atomic_helper.h>
>> +#include <drm/drm_crtc.h>
>> +#include <drm/drm_plane_helper.h>
>> +#include <drm/drmP.h>
>> +
>> +#include "sun4i_crtc.h"
>> +#include "sun8i_layer.h"
>> +#include "sun8i_mixer.h"
>> +
>> +struct sun8i_plane_desc {
>> +	       enum drm_plane_type     type;
>> +	       const uint32_t          *formats;
>> +	       uint32_t                nformats;
>> +};
>> +
>> +static int sun8i_mixer_layer_atomic_check(struct drm_plane *plane,
>> +					    struct drm_plane_state *state)
>> +{
>> +	return 0;
>> +}
>> +
>> +static void sun8i_mixer_layer_atomic_disable(struct drm_plane
>*plane,
>> +					       struct drm_plane_state *old_state)
>> +{
>> +	struct sun8i_layer *layer = plane_to_sun8i_layer(plane);
>> +	struct sun8i_mixer *mixer = layer->mixer;
>> +
>> +	sun8i_mixer_layer_enable(mixer, layer->id, false);
>> +}
>> +
>> +static void sun8i_mixer_layer_atomic_update(struct drm_plane *plane,
>> +					      struct drm_plane_state *old_state)
>> +{
>> +	struct sun8i_layer *layer = plane_to_sun8i_layer(plane);
>> +	struct sun8i_mixer *mixer = layer->mixer;
>> +
>> +	sun8i_mixer_update_layer_coord(mixer, layer->id, plane);
>> +	sun8i_mixer_update_layer_formats(mixer, layer->id, plane);
>> +	sun8i_mixer_update_layer_buffer(mixer, layer->id, plane);
>> +	sun8i_mixer_layer_enable(mixer, layer->id, true);
>> +}
>> +
>> +static struct drm_plane_helper_funcs sun8i_mixer_layer_helper_funcs
>= {
>> +	.atomic_check	= sun8i_mixer_layer_atomic_check,
>> +	.atomic_disable	= sun8i_mixer_layer_atomic_disable,
>> +	.atomic_update	= sun8i_mixer_layer_atomic_update,
>> +};
>> +
>> +static const struct drm_plane_funcs sun8i_mixer_layer_funcs = {
>> +	.atomic_destroy_state	= drm_atomic_helper_plane_destroy_state,
>> +	.atomic_duplicate_state	= drm_atomic_helper_plane_duplicate_state,
>> +	.destroy		= drm_plane_cleanup,
>> +	.disable_plane		= drm_atomic_helper_disable_plane,
>> +	.reset			= drm_atomic_helper_plane_reset,
>> +	.update_plane		= drm_atomic_helper_update_plane,
>> +};
>> +
>> +static const uint32_t sun8i_mixer_layer_formats[] = {
>> +	DRM_FORMAT_RGB888,
>> +	DRM_FORMAT_XRGB8888,
>> +};
>> +
>> +static const struct sun8i_plane_desc sun8i_mixer_planes[] = {
>> +	{
>> +		.type = DRM_PLANE_TYPE_PRIMARY,
>> +		.formats = sun8i_mixer_layer_formats,
>> +		.nformats = ARRAY_SIZE(sun8i_mixer_layer_formats),
>> +	},
>> +};
>> +
>> +static struct sun8i_layer *sun8i_layer_init_one(struct drm_device
>*drm,
>> +						struct sun8i_mixer *mixer,
>> +						const struct sun8i_plane_desc *plane)
>> +{
>> +	struct sun8i_layer *layer;
>> +	int ret;
>> +
>> +	layer = devm_kzalloc(drm->dev, sizeof(*layer), GFP_KERNEL);
>> +	if (!layer)
>> +		return ERR_PTR(-ENOMEM);
>> +
>> +	/* possible crtcs are set later */
>> +	ret = drm_universal_plane_init(drm, &layer->plane, 0,
>> +				       &sun8i_mixer_layer_funcs,
>> +				       plane->formats, plane->nformats,
>> +				       plane->type, NULL);
>> +	if (ret) {
>> +		dev_err(drm->dev, "Couldn't initialize layer\n");
>> +		return ERR_PTR(ret);
>> +	}
>> +
>> +	drm_plane_helper_add(&layer->plane,
>> +			     &sun8i_mixer_layer_helper_funcs);
>> +	layer->mixer = mixer;
>> +
>> +	return layer;
>> +}
>> +
>> +struct drm_plane **sun8i_layers_init(struct drm_device *drm,
>> +				     struct sun4i_crtc *crtc)
>> +{
>> +	struct drm_plane **planes;
>> +	struct sun8i_mixer *mixer = crtc->engine;
>> +	int i;
>> +
>> +	planes = devm_kcalloc(drm->dev, ARRAY_SIZE(sun8i_mixer_planes) + 1,
>> +			      sizeof(*planes), GFP_KERNEL);
>> +	if (!planes)
>> +		return ERR_PTR(-ENOMEM);
>> +
>> +	for (i = 0; i < ARRAY_SIZE(sun8i_mixer_planes); i++) {
>> +		const struct sun8i_plane_desc *plane = &sun8i_mixer_planes[i];
>> +		struct sun8i_layer *layer;
>> +
>> +		layer = sun8i_layer_init_one(drm, mixer, plane);
>> +		if (IS_ERR(layer)) {
>> +			dev_err(drm->dev, "Couldn't initialize %s plane\n",
>> +				i ? "overlay" : "primary");
>> +			return ERR_CAST(layer);
>> +		};
>> +
>> +		layer->id = i;
>> +		planes[i] = &layer->plane;
>> +	};
>> +
>> +	return planes;
>> +}
>> diff --git a/drivers/gpu/drm/sun4i/sun8i_layer.h
>b/drivers/gpu/drm/sun4i/sun8i_layer.h
>> new file mode 100644
>> index 000000000000..fe7e8a069d71
>> --- /dev/null
>> +++ b/drivers/gpu/drm/sun4i/sun8i_layer.h
>> @@ -0,0 +1,36 @@
>> +/*
>> + * Copyright (C) Icenowy Zheng <icenowy@aosc.io>
>> + *
>> + * Based on sun4i_layer.h, which is:
>> + *   Copyright (C) 2015 Free Electrons
>> + *   Copyright (C) 2015 NextThing Co
>> + *
>> + *   Maxime Ripard <maxime.ripard@free-electrons.com>
>> + *
>> + * This program is free software; you can redistribute it and/or
>> + * modify it under the terms of the GNU General Public License as
>> + * published by the Free Software Foundation; either version 2 of
>> + * the License, or (at your option) any later version.
>> + */
>> +
>> +#ifndef _SUN8I_LAYER_H_
>> +#define _SUN8I_LAYER_H_
>> +
>> +struct sun4i_crtc;
>> +
>> +struct sun8i_layer {
>> +	struct drm_plane	plane;
>> +	struct sun4i_drv	*drv;
>> +	struct sun8i_mixer	*mixer;
>> +	int			id;
>> +};
>> +
>> +static inline struct sun8i_layer *
>> +plane_to_sun8i_layer(struct drm_plane *plane)
>> +{
>> +	return container_of(plane, struct sun8i_layer, plane);
>> +}
>> +
>> +struct drm_plane **sun8i_layers_init(struct drm_device *drm,
>> +				     struct sun4i_crtc *crtc);
>> +#endif /* _SUN8I_LAYER_H_ */
>> diff --git a/drivers/gpu/drm/sun4i/sun8i_mixer.c
>b/drivers/gpu/drm/sun4i/sun8i_mixer.c
>> new file mode 100644
>> index 000000000000..5cff3f3833a7
>> --- /dev/null
>> +++ b/drivers/gpu/drm/sun4i/sun8i_mixer.c
>> @@ -0,0 +1,381 @@
>> +/*
>> + * Copyright (C) 2017 Icenowy Zheng <icenowy@aosc.io>
>> + *
>> + * Based on sun4i_backend.c, which is:
>> + *   Copyright (C) 2015 Free Electrons
>> + *   Copyright (C) 2015 NextThing Co
>> + *
>> + * This program is free software; you can redistribute it and/or
>> + * modify it under the terms of the GNU General Public License as
>> + * published by the Free Software Foundation; either version 2 of
>> + * the License, or (at your option) any later version.
>> + */
>> +
>> +#include <drm/drmP.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_gem_cma_helper.h>
>> +#include <drm/drm_plane_helper.h>
>> +
>> +#include <linux/component.h>
>> +#include <linux/reset.h>
>> +#include <linux/of_device.h>
>> +
>> +#include "sun4i_drv.h"
>> +#include "sun8i_mixer.h"
>> +#include "sun8i_layer.h"
>> +#include "sunxi_engine.h"
>> +
>> +void sun8i_mixer_commit(void *mixer)
>> +{
>> +	struct sun8i_mixer *sun8i_mixer = mixer;
>> +
>> +	DRM_DEBUG_DRIVER("Committing changes\n");
>> +
>> +	regmap_write(sun8i_mixer->regs, SUN8I_MIXER_GLOBAL_DBUFF,
>> +		     SUN8I_MIXER_GLOBAL_DBUFF_ENABLE);
>> +}
>> +
>> +void sun8i_mixer_layer_enable(struct sun8i_mixer *mixer,
>> +				int layer, bool enable)
>> +{
>> +	u32 val;
>> +	/* Currently the first UI channel is used */
>> +	int chan = mixer->cfg->vi_num;
>> +
>> +	DRM_DEBUG_DRIVER("Enabling layer %d in channel %d\n", layer, chan);
>> +
>> +	if (enable)
>> +		val = SUN8I_MIXER_CHAN_UI_LAYER_ATTR_EN;
>> +	else
>> +		val = 0;
>> +
>> +	regmap_update_bits(mixer->regs,
>> +			   SUN8I_MIXER_CHAN_UI_LAYER_ATTR(chan, layer),
>> +			   SUN8I_MIXER_CHAN_UI_LAYER_ATTR_EN, val);
>> +
>> +	/* Set the alpha configuration */
>> +	regmap_update_bits(mixer->regs,
>> +			   SUN8I_MIXER_CHAN_UI_LAYER_ATTR(chan, layer),
>> +			   SUN8I_MIXER_CHAN_UI_LAYER_ATTR_ALPHA_MODE_MASK,
>> +			   SUN8I_MIXER_CHAN_UI_LAYER_ATTR_ALPHA_MODE_DEF);
>> +	regmap_update_bits(mixer->regs,
>> +			   SUN8I_MIXER_CHAN_UI_LAYER_ATTR(chan, layer),
>> +			   SUN8I_MIXER_CHAN_UI_LAYER_ATTR_ALPHA_MASK,
>> +			   SUN8I_MIXER_CHAN_UI_LAYER_ATTR_ALPHA_DEF);
>> +}
>> +EXPORT_SYMBOL(sun8i_mixer_layer_enable);
>
>Why do you need to export it?

Oh... not needed. This export is dead code.

>
>> +
>> +static int sun8i_mixer_drm_format_to_layer(struct drm_plane *plane,
>> +					     u32 format, u32 *mode)
>> +{
>> +	switch (format) {
>> +	case DRM_FORMAT_XRGB8888:
>> +		*mode = SUN8I_MIXER_CHAN_UI_LAYER_ATTR_FBFMT_XRGB8888;
>> +		break;
>> +
>> +	case DRM_FORMAT_RGB888:
>> +		*mode = SUN8I_MIXER_CHAN_UI_LAYER_ATTR_FBFMT_RGB888;
>> +		break;
>> +
>> +	default:
>> +		return -EINVAL;
>> +	}
>> +
>> +	return 0;
>> +}
>> +
>> +int sun8i_mixer_update_layer_coord(struct sun8i_mixer *mixer,
>> +				     int layer, struct drm_plane *plane)
>> +{
>> +	struct drm_plane_state *state = plane->state;
>> +	struct drm_framebuffer *fb = state->fb;
>> +	/* Currently the first UI channel is used */
>> +	int chan = mixer->cfg->vi_num;
>> +
>> +	DRM_DEBUG_DRIVER("Updating layer %d\n", layer);
>> +
>> +	if (plane->type == DRM_PLANE_TYPE_PRIMARY) {
>> +		DRM_DEBUG_DRIVER("Primary layer, updating global size W: %u H:
>%u\n",
>> +				 state->crtc_w, state->crtc_h);
>> +		regmap_write(mixer->regs, SUN8I_MIXER_GLOBAL_SIZE,
>> +			     SUN8I_MIXER_SIZE(state->crtc_w,
>> +					      state->crtc_h));
>> +		DRM_DEBUG_DRIVER("Updating blender size\n");
>> +		regmap_write(mixer->regs,
>> +			     SUN8I_MIXER_BLEND_ATTR_INSIZE(0),
>> +			     SUN8I_MIXER_SIZE(state->crtc_w,
>> +					      state->crtc_h));
>> +		regmap_write(mixer->regs, SUN8I_MIXER_BLEND_OUTSIZE,
>> +			     SUN8I_MIXER_SIZE(state->crtc_w,
>> +					      state->crtc_h));
>> +		DRM_DEBUG_DRIVER("Updating channel size\n");
>> +		regmap_write(mixer->regs, SUN8I_MIXER_CHAN_UI_OVL_SIZE(chan),
>> +			     SUN8I_MIXER_SIZE(state->crtc_w,
>> +					      state->crtc_h));
>> +	}
>> +
>> +	/* Set the line width */
>> +	DRM_DEBUG_DRIVER("Layer line width: %d bytes\n", fb->pitches[0]);
>> +	regmap_write(mixer->regs, SUN8I_MIXER_CHAN_UI_LAYER_PITCH(chan,
>layer),
>> +		     fb->pitches[0]);
>> +
>> +	/* Set height and width */
>> +	DRM_DEBUG_DRIVER("Layer size W: %u H: %u\n",
>> +			 state->crtc_w, state->crtc_h);
>> +	regmap_write(mixer->regs, SUN8I_MIXER_CHAN_UI_LAYER_SIZE(chan,
>layer),
>> +		     SUN8I_MIXER_SIZE(state->crtc_w, state->crtc_h));
>> +
>> +	/* Set base coordinates */
>> +	DRM_DEBUG_DRIVER("Layer coordinates X: %d Y: %d\n",
>> +			 state->crtc_x, state->crtc_y);
>> +	regmap_write(mixer->regs, SUN8I_MIXER_CHAN_UI_LAYER_COORD(chan,
>layer),
>> +		     SUN8I_MIXER_COORD(state->crtc_x, state->crtc_y));
>> +
>> +	return 0;
>> +}
>> +EXPORT_SYMBOL(sun8i_mixer_update_layer_coord);
>> +
>> +int sun8i_mixer_update_layer_formats(struct sun8i_mixer *mixer,
>> +				       int layer, struct drm_plane *plane)
>> +{
>> +	struct drm_plane_state *state = plane->state;
>> +	struct drm_framebuffer *fb = state->fb;
>> +	bool interlaced = false;
>> +	u32 val;
>> +	/* Currently the first UI channel is used */
>> +	int chan = mixer->cfg->vi_num;
>> +	int ret;
>> +
>> +	if (plane->state->crtc)
>> +		interlaced = plane->state->crtc->state->adjusted_mode.flags
>> +			& DRM_MODE_FLAG_INTERLACE;
>> +
>> +	regmap_update_bits(mixer->regs, SUN8I_MIXER_BLEND_OUTCTL,
>> +			   SUN8I_MIXER_BLEND_OUTCTL_INTERLACED,
>> +			   interlaced ?
>> +			   SUN8I_MIXER_BLEND_OUTCTL_INTERLACED : 0);
>> +
>> +	DRM_DEBUG_DRIVER("Switching display mixer interlaced mode %s\n",
>> +			 interlaced ? "on" : "off");
>
>You're not using interlaced anywhere.

ok.

>
>> +
>> +	ret = sun8i_mixer_drm_format_to_layer(plane, fb->format->format,
>> +						&val);
>> +	if (ret) {
>> +		DRM_DEBUG_DRIVER("Invalid format\n");
>> +		return ret;
>> +	}
>> +
>> +	regmap_update_bits(mixer->regs,
>> +			   SUN8I_MIXER_CHAN_UI_LAYER_ATTR(chan, layer),
>> +			   SUN8I_MIXER_CHAN_UI_LAYER_ATTR_FBFMT_MASK, val);
>> +
>> +	return 0;
>> +}
>> +EXPORT_SYMBOL(sun8i_mixer_update_layer_formats);
>> +
>> +int sun8i_mixer_update_layer_buffer(struct sun8i_mixer *mixer,
>> +				      int layer, struct drm_plane *plane)
>> +{
>> +	struct drm_plane_state *state = plane->state;
>> +	struct drm_framebuffer *fb = state->fb;
>> +	struct drm_gem_cma_object *gem;
>> +	dma_addr_t paddr;
>> +	uint32_t paddr_u32;
>> +	/* Currently the first UI channel is used */
>> +	int chan = mixer->cfg->vi_num;
>> +	int bpp;
>> +
>> +	/* Get the physical address of the buffer in memory */
>> +	gem = drm_fb_cma_get_gem_obj(fb, 0);
>> +
>> +	DRM_DEBUG_DRIVER("Using GEM @ %pad\n", &gem->paddr);
>> +
>> +	/* Compute the start of the displayed memory */
>> +	bpp = fb->format->cpp[0];
>> +	paddr = gem->paddr + fb->offsets[0];
>> +	paddr += (state->src_x >> 16) * bpp;
>> +	paddr += (state->src_y >> 16) * fb->pitches[0];
>> +
>> +	DRM_DEBUG_DRIVER("Setting buffer address to %pad\n", &paddr);
>> +
>> +	paddr_u32 = (uint32_t) paddr;
>
>How does that work on 64-bits systems ?

The hardware is not designed to work on 64-bit systems.

Even 64-bit A64/H5 has also 3GiB memory limit.

The address cell in mixer hardware is also only 32-bit.

So we should just keep the force conversion here. If we then really met 4GiB-capable AW SoC without changing DE2, I think we should have other way to limit CMA pool inside 4GiB.

>
>> +
>> +	regmap_write(mixer->regs,
>> +		     SUN8I_MIXER_CHAN_UI_LAYER_TOP_LADDR(chan, layer),
>> +		     paddr_u32);
>> +
>> +	return 0;
>> +}
>> +EXPORT_SYMBOL(sun8i_mixer_update_layer_buffer);
>> +
>> +static const struct sunxi_engine_ops sun8i_engine_ops = {
>> +	.commit = sun8i_mixer_commit,
>> +	.layers_init = sun8i_layers_init,
>
>Align with tabs.
>
>> +};
>> +
>> +static struct regmap_config sun8i_mixer_regmap_config = {
>> +	.reg_bits	= 32,
>> +	.val_bits	= 32,
>> +	.reg_stride	= 4,
>> +	.max_register	= 0xbfffc, /* guessed */
>> +};
>> +
>> +static int sun8i_mixer_bind(struct device *dev, struct device
>*master,
>> +			      void *data)
>> +{
>> +	struct platform_device *pdev = to_platform_device(dev);
>> +	struct drm_device *drm = data;
>> +	struct sun4i_drv *drv = drm->dev_private;
>> +	struct sun8i_mixer *mixer;
>> +	struct resource *res;
>> +	void __iomem *regs;
>> +	int i, ret;
>> +
>> +	mixer = devm_kzalloc(dev, sizeof(*mixer), GFP_KERNEL);
>> +	if (!mixer)
>> +		return -ENOMEM;
>> +	dev_set_drvdata(dev, mixer);
>> +	drv->engine = mixer;
>> +	drv->engine_ops = &sun8i_engine_ops;
>> +
>> +	mixer->cfg = of_device_get_match_data(dev);
>> +	if (!mixer->cfg)
>> +		return -EINVAL;
>> +
>> +	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
>> +	regs = devm_ioremap_resource(dev, res);
>> +	if (IS_ERR(regs))
>> +		return PTR_ERR(regs);
>> +
>> +	mixer->regs = devm_regmap_init_mmio(dev, regs,
>> +					      &sun8i_mixer_regmap_config);
>> +	if (IS_ERR(mixer->regs)) {
>> +		dev_err(dev, "Couldn't create the mixer regmap\n");
>> +		return PTR_ERR(mixer->regs);
>> +	}
>> +
>> +	mixer->reset = devm_reset_control_get(dev, NULL);
>> +	if (IS_ERR(mixer->reset)) {
>> +		dev_err(dev, "Couldn't get our reset line\n");
>> +		return PTR_ERR(mixer->reset);
>> +	}
>> +
>> +	ret = reset_control_deassert(mixer->reset);
>> +	if (ret) {
>> +		dev_err(dev, "Couldn't deassert our reset line\n");
>> +		return ret;
>> +	}
>> +
>> +	mixer->bus_clk = devm_clk_get(dev, "bus");
>> +	if (IS_ERR(mixer->bus_clk)) {
>> +		dev_err(dev, "Couldn't get the mixer bus clock\n");
>> +		ret = PTR_ERR(mixer->bus_clk);
>> +		goto err_assert_reset;
>> +	}
>> +	clk_prepare_enable(mixer->bus_clk);
>> +
>> +	mixer->mod_clk = devm_clk_get(dev, "mod");
>> +	if (IS_ERR(mixer->mod_clk)) {
>> +		dev_err(dev, "Couldn't get the mixer module clock\n");
>> +		ret = PTR_ERR(mixer->mod_clk);
>> +		goto err_disable_bus_clk;
>> +	}
>> +	clk_prepare_enable(mixer->mod_clk);
>> +
>> +	/* Reset the registers */
>> +	for (i = 0x0; i < 0x20000; i += 4)
>> +		regmap_write(mixer->regs, i, 0);
>> +
>> +	/* Enable the mixer */
>> +	regmap_write(mixer->regs, SUN8I_MIXER_GLOBAL_CTL,
>> +		     SUN8I_MIXER_GLOBAL_CTL_RT_EN);
>> +
>> +	/* Initialize blender */
>> +	regmap_write(mixer->regs, SUN8I_MIXER_BLEND_FCOLOR_CTL,
>> +		     SUN8I_MIXER_BLEND_FCOLOR_CTL_DEF);
>> +	regmap_write(mixer->regs, SUN8I_MIXER_BLEND_PREMULTIPLY,
>> +		     SUN8I_MIXER_BLEND_PREMULTIPLY_DEF);
>> +	regmap_write(mixer->regs, SUN8I_MIXER_BLEND_BKCOLOR,
>> +		     SUN8I_MIXER_BLEND_BKCOLOR_DEF);
>> +	regmap_write(mixer->regs, SUN8I_MIXER_BLEND_MODE(0),
>> +		     SUN8I_MIXER_BLEND_MODE_DEF);
>> +	regmap_write(mixer->regs, SUN8I_MIXER_BLEND_CK_CTL,
>> +		     SUN8I_MIXER_BLEND_CK_CTL_DEF);
>> +
>> +	regmap_write(mixer->regs,
>> +		     SUN8I_MIXER_BLEND_ATTR_FCOLOR(0),
>> +		     SUN8I_MIXER_BLEND_ATTR_FCOLOR_DEF);
>> +
>> +	/* Select the first UI channel */
>> +	DRM_DEBUG_DRIVER("Selecting channel %d (first UI channel)\n",
>> +			 mixer->cfg->vi_num);
>> +	regmap_write(mixer->regs, SUN8I_MIXER_BLEND_ROUTE,
>> +		     mixer->cfg->vi_num);
>> +
>> +	return 0;
>> +
>> +	clk_disable_unprepare(mixer->mod_clk);
>> +err_disable_bus_clk:
>> +	clk_disable_unprepare(mixer->bus_clk);
>> +err_assert_reset:
>> +	reset_control_assert(mixer->reset);
>> +	return ret;
>> +}
>> +
>> +static void sun8i_mixer_unbind(struct device *dev, struct device
>*master,
>> +				 void *data)
>> +{
>> +	struct sun8i_mixer *mixer = dev_get_drvdata(dev);
>> +
>> +	clk_disable_unprepare(mixer->mod_clk);
>> +	clk_disable_unprepare(mixer->bus_clk);
>> +	reset_control_assert(mixer->reset);
>> +}
>> +
>> +static const struct component_ops sun8i_mixer_ops = {
>> +	.bind	= sun8i_mixer_bind,
>> +	.unbind	= sun8i_mixer_unbind,
>> +};
>> +
>> +static int sun8i_mixer_probe(struct platform_device *pdev)
>> +{
>> +	return component_add(&pdev->dev, &sun8i_mixer_ops);
>> +}
>> +
>> +static int sun8i_mixer_remove(struct platform_device *pdev)
>> +{
>> +	component_del(&pdev->dev, &sun8i_mixer_ops);
>> +
>> +	return 0;
>> +}
>> +
>> +static const struct sun8i_mixer_cfg sun8i_v3s_mixer_cfg = {
>> +	.vi_num = 2,
>> +	.ui_num = 1,
>> +};
>> +
>> +static const struct of_device_id sun8i_mixer_of_table[] = {
>> +	{
>> +		.compatible = "allwinner,sun8i-v3s-de2-mixer",
>> +		.data = &sun8i_v3s_mixer_cfg,
>> +	},
>> +	{ }
>> +};
>> +MODULE_DEVICE_TABLE(of, sun8i_mixer_of_table);
>> +
>> +static struct platform_driver sun8i_mixer_platform_driver = {
>> +	.probe		= sun8i_mixer_probe,
>> +	.remove		= sun8i_mixer_remove,
>> +	.driver		= {
>> +		.name		= "sun8i-mixer",
>> +		.of_match_table	= sun8i_mixer_of_table,
>> +	},
>> +};
>> +module_platform_driver(sun8i_mixer_platform_driver);
>> +
>> +MODULE_AUTHOR("Icenowy Zheng <icenowy@aosc.io>");
>> +MODULE_DESCRIPTION("Allwinner DE2 Mixer driver");
>> +MODULE_LICENSE("GPL");
>> diff --git a/drivers/gpu/drm/sun4i/sun8i_mixer.h
>b/drivers/gpu/drm/sun4i/sun8i_mixer.h
>> new file mode 100644
>> index 000000000000..a4a365ae44c9
>> --- /dev/null
>> +++ b/drivers/gpu/drm/sun4i/sun8i_mixer.h
>> @@ -0,0 +1,131 @@
>> +/*
>> + * Copyright (C) 2017 Icenowy Zheng <icenowy@aosc.io>
>> + *
>> + * This program is free software; you can redistribute it and/or
>> + * modify it under the terms of the GNU General Public License as
>> + * published by the Free Software Foundation; either version 2 of
>> + * the License, or (at your option) any later version.
>> + */
>> +
>> +#ifndef _SUN8I_MIXER_H_
>> +#define _SUN8I_MIXER_H_
>> +
>> +#include <linux/clk.h>
>> +#include <linux/regmap.h>
>> +#include <linux/reset.h>
>> +
>> +#include "sun4i_layer.h"
>> +
>> +#define SUN8I_MIXER_MAX_CHAN_COUNT		4
>> +
>> +#define SUN8I_MIXER_SIZE(w, h)			(((h) - 1) << 16 | ((w) - 1))
>> +#define SUN8I_MIXER_COORD(x, y)			((y) << 16 | (x))
>> +
>> +#define SUN8I_MIXER_GLOBAL_CTL			0x0
>> +#define SUN8I_MIXER_GLOBAL_STATUS		0x4
>> +#define SUN8I_MIXER_GLOBAL_DBUFF		0x8
>> +#define SUN8I_MIXER_GLOBAL_SIZE			0xc
>> +
>> +#define SUN8I_MIXER_GLOBAL_CTL_RT_EN		0x1
>> +
>> +#define SUN8I_MIXER_GLOBAL_DBUFF_ENABLE		0x1
>> +
>> +#define SUN8I_MIXER_BLEND_FCOLOR_CTL		0x1000
>> +#define SUN8I_MIXER_BLEND_ATTR_FCOLOR(x)	(0x1004 + 0x10 * (x) + 0x0)
>> +#define SUN8I_MIXER_BLEND_ATTR_INSIZE(x)	(0x1004 + 0x10 * (x) + 0x4)
>> +#define SUN8I_MIXER_BLEND_ATTR_OFFSET(x)	(0x1004 + 0x10 * (x) + 0x8)
>> +#define SUN8I_MIXER_BLEND_ROUTE			0x1080
>> +#define SUN8I_MIXER_BLEND_PREMULTIPLY		0x1084
>> +#define SUN8I_MIXER_BLEND_BKCOLOR		0x1088
>> +#define SUN8I_MIXER_BLEND_OUTSIZE		0x108c
>> +#define SUN8I_MIXER_BLEND_MODE(x)		(0x1090 + 0x04 * (x))
>> +#define SUN8I_MIXER_BLEND_CK_CTL		0x10b0
>> +#define SUN8I_MIXER_BLEND_CK_CFG		0x10b4
>> +#define SUN8I_MIXER_BLEND_CK_MAX(x)		(0x10c0 + 0x04 * (x))
>> +#define SUN8I_MIXER_BLEND_CK_MIN(x)		(0x10e0 + 0x04 * (x))
>> +#define SUN8I_MIXER_BLEND_OUTCTL		0x10fc
>> +
>> +/* The following numbers are some still unknown magic numbers */
>> +#define SUN8I_MIXER_BLEND_ATTR_FCOLOR_DEF	0xff000000
>> +#define SUN8I_MIXER_BLEND_FCOLOR_CTL_DEF	0x00000101
>> +#define SUN8I_MIXER_BLEND_PREMULTIPLY_DEF	0x0
>> +#define SUN8I_MIXER_BLEND_BKCOLOR_DEF		0xff000000
>> +#define SUN8I_MIXER_BLEND_MODE_DEF		0x03010301
>> +#define SUN8I_MIXER_BLEND_CK_CTL_DEF		0x0
>> +
>> +#define SUN8I_MIXER_BLEND_OUTCTL_INTERLACED	BIT(1)
>> +
>> +/*
>> + * VI channels are not used now, but the support of them may be
>introduced in
>> + * the future.
>> + */
>> +
>> +#define SUN8I_MIXER_CHAN_UI_LAYER_ATTR(ch, layer) \
>> +			(0x2000 + 0x1000 * (ch) + 0x20 * (layer) + 0x0)
>> +#define SUN8I_MIXER_CHAN_UI_LAYER_SIZE(ch, layer) \
>> +			(0x2000 + 0x1000 * (ch) + 0x20 * (layer) + 0x4)
>> +#define SUN8I_MIXER_CHAN_UI_LAYER_COORD(ch, layer) \
>> +			(0x2000 + 0x1000 * (ch) + 0x20 * (layer) + 0x8)
>> +#define SUN8I_MIXER_CHAN_UI_LAYER_PITCH(ch, layer) \
>> +			(0x2000 + 0x1000 * (ch) + 0x20 * (layer) + 0xc)
>> +#define SUN8I_MIXER_CHAN_UI_LAYER_TOP_LADDR(ch, layer) \
>> +			(0x2000 + 0x1000 * (ch) + 0x20 * (layer) + 0x10)
>> +#define SUN8I_MIXER_CHAN_UI_LAYER_BOT_LADDR(ch, layer) \
>> +			(0x2000 + 0x1000 * (ch) + 0x20 * (layer) + 0x14)
>> +#define SUN8I_MIXER_CHAN_UI_LAYER_FCOLOR(ch, layer) \
>> +			(0x2000 + 0x1000 * (ch) + 0x20 * (layer) + 0x18)
>> +#define SUN8I_MIXER_CHAN_UI_TOP_HADDR(ch)	(0x2000 + 0x1000 * (ch) +
>0x80)
>> +#define SUN8I_MIXER_CHAN_UI_BOT_HADDR(ch)	(0x2000 + 0x1000 * (ch) +
>0x84)
>> +#define SUN8I_MIXER_CHAN_UI_OVL_SIZE(ch)	(0x2000 + 0x1000 * (ch) +
>0x88)
>> +
>> +#define SUN8I_MIXER_CHAN_UI_LAYER_ATTR_EN		BIT(0)
>> +#define SUN8I_MIXER_CHAN_UI_LAYER_ATTR_ALPHA_MODE_MASK	GENMASK(2, 1)
>> +#define SUN8I_MIXER_CHAN_UI_LAYER_ATTR_FBFMT_MASK	GENMASK(11, 8)
>> +#define SUN8I_MIXER_CHAN_UI_LAYER_ATTR_ALPHA_MASK	GENMASK(31, 24)
>> +#define SUN8I_MIXER_CHAN_UI_LAYER_ATTR_ALPHA_MODE_DEF	(1 << 1)
>> +#define SUN8I_MIXER_CHAN_UI_LAYER_ATTR_FBFMT_ARGB8888	(0 << 8)
>> +#define SUN8I_MIXER_CHAN_UI_LAYER_ATTR_FBFMT_XRGB8888	(4 << 8)
>> +#define SUN8I_MIXER_CHAN_UI_LAYER_ATTR_FBFMT_RGB888	(8 << 8)
>> +#define SUN8I_MIXER_CHAN_UI_LAYER_ATTR_ALPHA_DEF	(0xff << 24)
>> +
>> +/*
>> + * These sub-engines are still unknown now, the EN registers are
>here only to
>> + * be used to disable these sub-engines.
>> + */
>> +#define SUN8I_MIXER_VSU_EN			0x20000
>> +#define SUN8I_MIXER_GSU1_EN			0x30000
>> +#define SUN8I_MIXER_GSU2_EN			0x40000
>> +#define SUN8I_MIXER_GSU3_EN			0x50000
>> +#define SUN8I_MIXER_FCE_EN			0xa0000
>> +#define SUN8I_MIXER_BWS_EN			0xa2000
>> +#define SUN8I_MIXER_LTI_EN			0xa4000
>> +#define SUN8I_MIXER_PEAK_EN			0xa6000
>> +#define SUN8I_MIXER_ASE_EN			0xa8000
>> +#define SUN8I_MIXER_FCC_EN			0xaa000
>> +#define SUN8I_MIXER_DCSC_EN			0xb0000
>> +
>> +struct sun8i_mixer_cfg {
>> +	int		vi_num;
>> +	int		ui_num;
>> +};
>> +
>> +struct sun8i_mixer {
>> +	struct regmap			*regs;
>> +
>> +	const struct sun8i_mixer_cfg	*cfg;
>> +
>> +	struct reset_control		*reset;
>> +
>> +	struct clk			*bus_clk;
>> +	struct clk			*mod_clk;
>> +};
>> +
>> +void sun8i_mixer_layer_enable(struct sun8i_mixer *mixer,
>> +				int layer, bool enable);
>> +int sun8i_mixer_update_layer_coord(struct sun8i_mixer *mixer,
>> +				     int layer, struct drm_plane *plane);
>> +int sun8i_mixer_update_layer_formats(struct sun8i_mixer *mixer,
>> +				       int layer, struct drm_plane *plane);
>> +int sun8i_mixer_update_layer_buffer(struct sun8i_mixer *mixer,
>> +				      int layer, struct drm_plane *plane);
>> +#endif /* _SUN8I_MIXER_H_ */
>
>Thanks,
>Maxime

WARNING: multiple messages have this Message-ID (diff)
From: Icenowy Zheng <icenowy-h8G6r0blFSE@public.gmane.org>
To: Maxime Ripard
	<maxime.ripard-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@public.gmane.org>
Cc: devicetree-u79uwXL29TY76Z2rM5mHXA@public.gmane.org,
	Jernej Skrabec <jernej.skrabec-gGgVlfcn5nU@public.gmane.org>,
	David Airlie <airlied-cv59FeDIM0c@public.gmane.org>,
	linux-sunxi-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA@public.gmane.org,
	dri-devel-PD4FTy7X32lNgt0PjOBp9y5qC8QIuHrW@public.gmane.org,
	Chen-Yu Tsai <wens-jdAy2FN1RRM@public.gmane.org>,
	Rob Herring <robh+dt-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org>,
	linux-clk-u79uwXL29TY76Z2rM5mHXA@public.gmane.org,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r@public.gmane.org
Subject: Re: [PATCH v4 06/11] drm/sun4i: add support for Allwinner DE2 mixers
Date: Tue, 18 Apr 2017 18:47:56 +0800	[thread overview]
Message-ID: <88F5FAC9-1873-4C76-9AB9-FF361C07664E@aosc.io> (raw)
In-Reply-To: <20170418090047.7i2k6dtoqxfdqwwy@lukather>



于 2017年4月18日 GMT+08:00 下午5:00:47, Maxime Ripard <maxime.ripard-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@public.gmane.org> 写到:
>On Sun, Apr 16, 2017 at 08:08:44PM +0800, Icenowy Zheng wrote:
>> Allwinner have a new "Display Engine 2.0" in their new SoCs, which
>comes
>> with mixers to do graphic processing and feed data to TCON, like the
>old
>> backends and frontends.
>> 
>> Add support for the mixer on Allwinner V3s SoC; it's the simplest
>one.
>> 
>> Currently a lot of functions are still missing -- more investigations
>> are needed to gain enough information for them.
>> 
>> Signed-off-by: Icenowy Zheng <icenowy-h8G6r0blFSE@public.gmane.org>
>> ---
>> Changes in v4:
>> - Killed some dead code according to Jernej.
>> 
>>  drivers/gpu/drm/sun4i/Kconfig       |  10 +
>>  drivers/gpu/drm/sun4i/Makefile      |   4 +
>>  drivers/gpu/drm/sun4i/sun8i_layer.c | 142 ++++++++++++++
>>  drivers/gpu/drm/sun4i/sun8i_layer.h |  36 ++++
>>  drivers/gpu/drm/sun4i/sun8i_mixer.c | 381
>++++++++++++++++++++++++++++++++++++
>>  drivers/gpu/drm/sun4i/sun8i_mixer.h | 131 +++++++++++++
>>  6 files changed, 704 insertions(+)
>>  create mode 100644 drivers/gpu/drm/sun4i/sun8i_layer.c
>>  create mode 100644 drivers/gpu/drm/sun4i/sun8i_layer.h
>>  create mode 100644 drivers/gpu/drm/sun4i/sun8i_mixer.c
>>  create mode 100644 drivers/gpu/drm/sun4i/sun8i_mixer.h
>> 
>> diff --git a/drivers/gpu/drm/sun4i/Kconfig
>b/drivers/gpu/drm/sun4i/Kconfig
>> index 5a8227f37cc4..15557484520d 100644
>> --- a/drivers/gpu/drm/sun4i/Kconfig
>> +++ b/drivers/gpu/drm/sun4i/Kconfig
>> @@ -22,3 +22,13 @@ config DRM_SUN4I_BACKEND
>>  	  original Allwinner Display Engine, which has a backend to
>>  	  do some alpha blending and feed graphics to TCON. If M is
>>  	  selected the module will be called sun4i-backend.
>> +
>> +config DRM_SUN4I_SUN8I_MIXER
>> +	tristate "Support for Allwinner Display Engine 2.0 Mixer"
>> +	depends on DRM_SUN4I
>> +	default MACH_SUN8I
>> +	help
>> +	  Choose this option if you have an Allwinner SoC with the
>> +	  Allwinner Display Engine 2.0, which has a mixer to do some
>> +	  graphics mixture and feed graphics to TCON, If M is
>> +	  selected the module will be called sun8i-mixer.
>> diff --git a/drivers/gpu/drm/sun4i/Makefile
>b/drivers/gpu/drm/sun4i/Makefile
>> index 1db1068b9be1..7625c2dad1bb 100644
>> --- a/drivers/gpu/drm/sun4i/Makefile
>> +++ b/drivers/gpu/drm/sun4i/Makefile
>> @@ -9,7 +9,11 @@ sun4i-tcon-y += sun4i_crtc.o
>>  sun4i-backend-y += sun4i_layer.o
>>  sun4i-backend-y += sun4i_backend.o
>>  
>> +sun8i-mixer-y += sun8i_layer.o
>> +sun8i-mixer-y += sun8i_mixer.o
>> +
>>  obj-$(CONFIG_DRM_SUN4I)		+= sun4i-drm.o sun4i-tcon.o
>>  obj-$(CONFIG_DRM_SUN4I_BACKEND)	+= sun4i-backend.o
>> +obj-$(CONFIG_DRM_SUN4I_SUN8I_MIXER) += sun8i-mixer.o
>
>Please align the value using tabs.

Should I re-align existed items?

>
>>  obj-$(CONFIG_DRM_SUN4I)		+= sun6i_drc.o
>>  obj-$(CONFIG_DRM_SUN4I)		+= sun4i_tv.o
>> diff --git a/drivers/gpu/drm/sun4i/sun8i_layer.c
>b/drivers/gpu/drm/sun4i/sun8i_layer.c
>> new file mode 100644
>> index 000000000000..d70a90d963b0
>> --- /dev/null
>> +++ b/drivers/gpu/drm/sun4i/sun8i_layer.c
>> @@ -0,0 +1,142 @@
>> +/*
>> + * Copyright (C) Icenowy Zheng <icenowy-h8G6r0blFSE@public.gmane.org>
>> + *
>> + * Based on sun4i_layer.h, which is:
>> + *   Copyright (C) 2015 Free Electrons
>> + *   Copyright (C) 2015 NextThing Co
>> + *
>> + *   Maxime Ripard <maxime.ripard-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@public.gmane.org>
>> + *
>> + * This program is free software; you can redistribute it and/or
>> + * modify it under the terms of the GNU General Public License as
>> + * published by the Free Software Foundation; either version 2 of
>> + * the License, or (at your option) any later version.
>> + */
>> +
>> +#include <drm/drm_atomic_helper.h>
>> +#include <drm/drm_crtc.h>
>> +#include <drm/drm_plane_helper.h>
>> +#include <drm/drmP.h>
>> +
>> +#include "sun4i_crtc.h"
>> +#include "sun8i_layer.h"
>> +#include "sun8i_mixer.h"
>> +
>> +struct sun8i_plane_desc {
>> +	       enum drm_plane_type     type;
>> +	       const uint32_t          *formats;
>> +	       uint32_t                nformats;
>> +};
>> +
>> +static int sun8i_mixer_layer_atomic_check(struct drm_plane *plane,
>> +					    struct drm_plane_state *state)
>> +{
>> +	return 0;
>> +}
>> +
>> +static void sun8i_mixer_layer_atomic_disable(struct drm_plane
>*plane,
>> +					       struct drm_plane_state *old_state)
>> +{
>> +	struct sun8i_layer *layer = plane_to_sun8i_layer(plane);
>> +	struct sun8i_mixer *mixer = layer->mixer;
>> +
>> +	sun8i_mixer_layer_enable(mixer, layer->id, false);
>> +}
>> +
>> +static void sun8i_mixer_layer_atomic_update(struct drm_plane *plane,
>> +					      struct drm_plane_state *old_state)
>> +{
>> +	struct sun8i_layer *layer = plane_to_sun8i_layer(plane);
>> +	struct sun8i_mixer *mixer = layer->mixer;
>> +
>> +	sun8i_mixer_update_layer_coord(mixer, layer->id, plane);
>> +	sun8i_mixer_update_layer_formats(mixer, layer->id, plane);
>> +	sun8i_mixer_update_layer_buffer(mixer, layer->id, plane);
>> +	sun8i_mixer_layer_enable(mixer, layer->id, true);
>> +}
>> +
>> +static struct drm_plane_helper_funcs sun8i_mixer_layer_helper_funcs
>= {
>> +	.atomic_check	= sun8i_mixer_layer_atomic_check,
>> +	.atomic_disable	= sun8i_mixer_layer_atomic_disable,
>> +	.atomic_update	= sun8i_mixer_layer_atomic_update,
>> +};
>> +
>> +static const struct drm_plane_funcs sun8i_mixer_layer_funcs = {
>> +	.atomic_destroy_state	= drm_atomic_helper_plane_destroy_state,
>> +	.atomic_duplicate_state	= drm_atomic_helper_plane_duplicate_state,
>> +	.destroy		= drm_plane_cleanup,
>> +	.disable_plane		= drm_atomic_helper_disable_plane,
>> +	.reset			= drm_atomic_helper_plane_reset,
>> +	.update_plane		= drm_atomic_helper_update_plane,
>> +};
>> +
>> +static const uint32_t sun8i_mixer_layer_formats[] = {
>> +	DRM_FORMAT_RGB888,
>> +	DRM_FORMAT_XRGB8888,
>> +};
>> +
>> +static const struct sun8i_plane_desc sun8i_mixer_planes[] = {
>> +	{
>> +		.type = DRM_PLANE_TYPE_PRIMARY,
>> +		.formats = sun8i_mixer_layer_formats,
>> +		.nformats = ARRAY_SIZE(sun8i_mixer_layer_formats),
>> +	},
>> +};
>> +
>> +static struct sun8i_layer *sun8i_layer_init_one(struct drm_device
>*drm,
>> +						struct sun8i_mixer *mixer,
>> +						const struct sun8i_plane_desc *plane)
>> +{
>> +	struct sun8i_layer *layer;
>> +	int ret;
>> +
>> +	layer = devm_kzalloc(drm->dev, sizeof(*layer), GFP_KERNEL);
>> +	if (!layer)
>> +		return ERR_PTR(-ENOMEM);
>> +
>> +	/* possible crtcs are set later */
>> +	ret = drm_universal_plane_init(drm, &layer->plane, 0,
>> +				       &sun8i_mixer_layer_funcs,
>> +				       plane->formats, plane->nformats,
>> +				       plane->type, NULL);
>> +	if (ret) {
>> +		dev_err(drm->dev, "Couldn't initialize layer\n");
>> +		return ERR_PTR(ret);
>> +	}
>> +
>> +	drm_plane_helper_add(&layer->plane,
>> +			     &sun8i_mixer_layer_helper_funcs);
>> +	layer->mixer = mixer;
>> +
>> +	return layer;
>> +}
>> +
>> +struct drm_plane **sun8i_layers_init(struct drm_device *drm,
>> +				     struct sun4i_crtc *crtc)
>> +{
>> +	struct drm_plane **planes;
>> +	struct sun8i_mixer *mixer = crtc->engine;
>> +	int i;
>> +
>> +	planes = devm_kcalloc(drm->dev, ARRAY_SIZE(sun8i_mixer_planes) + 1,
>> +			      sizeof(*planes), GFP_KERNEL);
>> +	if (!planes)
>> +		return ERR_PTR(-ENOMEM);
>> +
>> +	for (i = 0; i < ARRAY_SIZE(sun8i_mixer_planes); i++) {
>> +		const struct sun8i_plane_desc *plane = &sun8i_mixer_planes[i];
>> +		struct sun8i_layer *layer;
>> +
>> +		layer = sun8i_layer_init_one(drm, mixer, plane);
>> +		if (IS_ERR(layer)) {
>> +			dev_err(drm->dev, "Couldn't initialize %s plane\n",
>> +				i ? "overlay" : "primary");
>> +			return ERR_CAST(layer);
>> +		};
>> +
>> +		layer->id = i;
>> +		planes[i] = &layer->plane;
>> +	};
>> +
>> +	return planes;
>> +}
>> diff --git a/drivers/gpu/drm/sun4i/sun8i_layer.h
>b/drivers/gpu/drm/sun4i/sun8i_layer.h
>> new file mode 100644
>> index 000000000000..fe7e8a069d71
>> --- /dev/null
>> +++ b/drivers/gpu/drm/sun4i/sun8i_layer.h
>> @@ -0,0 +1,36 @@
>> +/*
>> + * Copyright (C) Icenowy Zheng <icenowy-h8G6r0blFSE@public.gmane.org>
>> + *
>> + * Based on sun4i_layer.h, which is:
>> + *   Copyright (C) 2015 Free Electrons
>> + *   Copyright (C) 2015 NextThing Co
>> + *
>> + *   Maxime Ripard <maxime.ripard-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@public.gmane.org>
>> + *
>> + * This program is free software; you can redistribute it and/or
>> + * modify it under the terms of the GNU General Public License as
>> + * published by the Free Software Foundation; either version 2 of
>> + * the License, or (at your option) any later version.
>> + */
>> +
>> +#ifndef _SUN8I_LAYER_H_
>> +#define _SUN8I_LAYER_H_
>> +
>> +struct sun4i_crtc;
>> +
>> +struct sun8i_layer {
>> +	struct drm_plane	plane;
>> +	struct sun4i_drv	*drv;
>> +	struct sun8i_mixer	*mixer;
>> +	int			id;
>> +};
>> +
>> +static inline struct sun8i_layer *
>> +plane_to_sun8i_layer(struct drm_plane *plane)
>> +{
>> +	return container_of(plane, struct sun8i_layer, plane);
>> +}
>> +
>> +struct drm_plane **sun8i_layers_init(struct drm_device *drm,
>> +				     struct sun4i_crtc *crtc);
>> +#endif /* _SUN8I_LAYER_H_ */
>> diff --git a/drivers/gpu/drm/sun4i/sun8i_mixer.c
>b/drivers/gpu/drm/sun4i/sun8i_mixer.c
>> new file mode 100644
>> index 000000000000..5cff3f3833a7
>> --- /dev/null
>> +++ b/drivers/gpu/drm/sun4i/sun8i_mixer.c
>> @@ -0,0 +1,381 @@
>> +/*
>> + * Copyright (C) 2017 Icenowy Zheng <icenowy-h8G6r0blFSE@public.gmane.org>
>> + *
>> + * Based on sun4i_backend.c, which is:
>> + *   Copyright (C) 2015 Free Electrons
>> + *   Copyright (C) 2015 NextThing Co
>> + *
>> + * This program is free software; you can redistribute it and/or
>> + * modify it under the terms of the GNU General Public License as
>> + * published by the Free Software Foundation; either version 2 of
>> + * the License, or (at your option) any later version.
>> + */
>> +
>> +#include <drm/drmP.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_gem_cma_helper.h>
>> +#include <drm/drm_plane_helper.h>
>> +
>> +#include <linux/component.h>
>> +#include <linux/reset.h>
>> +#include <linux/of_device.h>
>> +
>> +#include "sun4i_drv.h"
>> +#include "sun8i_mixer.h"
>> +#include "sun8i_layer.h"
>> +#include "sunxi_engine.h"
>> +
>> +void sun8i_mixer_commit(void *mixer)
>> +{
>> +	struct sun8i_mixer *sun8i_mixer = mixer;
>> +
>> +	DRM_DEBUG_DRIVER("Committing changes\n");
>> +
>> +	regmap_write(sun8i_mixer->regs, SUN8I_MIXER_GLOBAL_DBUFF,
>> +		     SUN8I_MIXER_GLOBAL_DBUFF_ENABLE);
>> +}
>> +
>> +void sun8i_mixer_layer_enable(struct sun8i_mixer *mixer,
>> +				int layer, bool enable)
>> +{
>> +	u32 val;
>> +	/* Currently the first UI channel is used */
>> +	int chan = mixer->cfg->vi_num;
>> +
>> +	DRM_DEBUG_DRIVER("Enabling layer %d in channel %d\n", layer, chan);
>> +
>> +	if (enable)
>> +		val = SUN8I_MIXER_CHAN_UI_LAYER_ATTR_EN;
>> +	else
>> +		val = 0;
>> +
>> +	regmap_update_bits(mixer->regs,
>> +			   SUN8I_MIXER_CHAN_UI_LAYER_ATTR(chan, layer),
>> +			   SUN8I_MIXER_CHAN_UI_LAYER_ATTR_EN, val);
>> +
>> +	/* Set the alpha configuration */
>> +	regmap_update_bits(mixer->regs,
>> +			   SUN8I_MIXER_CHAN_UI_LAYER_ATTR(chan, layer),
>> +			   SUN8I_MIXER_CHAN_UI_LAYER_ATTR_ALPHA_MODE_MASK,
>> +			   SUN8I_MIXER_CHAN_UI_LAYER_ATTR_ALPHA_MODE_DEF);
>> +	regmap_update_bits(mixer->regs,
>> +			   SUN8I_MIXER_CHAN_UI_LAYER_ATTR(chan, layer),
>> +			   SUN8I_MIXER_CHAN_UI_LAYER_ATTR_ALPHA_MASK,
>> +			   SUN8I_MIXER_CHAN_UI_LAYER_ATTR_ALPHA_DEF);
>> +}
>> +EXPORT_SYMBOL(sun8i_mixer_layer_enable);
>
>Why do you need to export it?

Oh... not needed. This export is dead code.

>
>> +
>> +static int sun8i_mixer_drm_format_to_layer(struct drm_plane *plane,
>> +					     u32 format, u32 *mode)
>> +{
>> +	switch (format) {
>> +	case DRM_FORMAT_XRGB8888:
>> +		*mode = SUN8I_MIXER_CHAN_UI_LAYER_ATTR_FBFMT_XRGB8888;
>> +		break;
>> +
>> +	case DRM_FORMAT_RGB888:
>> +		*mode = SUN8I_MIXER_CHAN_UI_LAYER_ATTR_FBFMT_RGB888;
>> +		break;
>> +
>> +	default:
>> +		return -EINVAL;
>> +	}
>> +
>> +	return 0;
>> +}
>> +
>> +int sun8i_mixer_update_layer_coord(struct sun8i_mixer *mixer,
>> +				     int layer, struct drm_plane *plane)
>> +{
>> +	struct drm_plane_state *state = plane->state;
>> +	struct drm_framebuffer *fb = state->fb;
>> +	/* Currently the first UI channel is used */
>> +	int chan = mixer->cfg->vi_num;
>> +
>> +	DRM_DEBUG_DRIVER("Updating layer %d\n", layer);
>> +
>> +	if (plane->type == DRM_PLANE_TYPE_PRIMARY) {
>> +		DRM_DEBUG_DRIVER("Primary layer, updating global size W: %u H:
>%u\n",
>> +				 state->crtc_w, state->crtc_h);
>> +		regmap_write(mixer->regs, SUN8I_MIXER_GLOBAL_SIZE,
>> +			     SUN8I_MIXER_SIZE(state->crtc_w,
>> +					      state->crtc_h));
>> +		DRM_DEBUG_DRIVER("Updating blender size\n");
>> +		regmap_write(mixer->regs,
>> +			     SUN8I_MIXER_BLEND_ATTR_INSIZE(0),
>> +			     SUN8I_MIXER_SIZE(state->crtc_w,
>> +					      state->crtc_h));
>> +		regmap_write(mixer->regs, SUN8I_MIXER_BLEND_OUTSIZE,
>> +			     SUN8I_MIXER_SIZE(state->crtc_w,
>> +					      state->crtc_h));
>> +		DRM_DEBUG_DRIVER("Updating channel size\n");
>> +		regmap_write(mixer->regs, SUN8I_MIXER_CHAN_UI_OVL_SIZE(chan),
>> +			     SUN8I_MIXER_SIZE(state->crtc_w,
>> +					      state->crtc_h));
>> +	}
>> +
>> +	/* Set the line width */
>> +	DRM_DEBUG_DRIVER("Layer line width: %d bytes\n", fb->pitches[0]);
>> +	regmap_write(mixer->regs, SUN8I_MIXER_CHAN_UI_LAYER_PITCH(chan,
>layer),
>> +		     fb->pitches[0]);
>> +
>> +	/* Set height and width */
>> +	DRM_DEBUG_DRIVER("Layer size W: %u H: %u\n",
>> +			 state->crtc_w, state->crtc_h);
>> +	regmap_write(mixer->regs, SUN8I_MIXER_CHAN_UI_LAYER_SIZE(chan,
>layer),
>> +		     SUN8I_MIXER_SIZE(state->crtc_w, state->crtc_h));
>> +
>> +	/* Set base coordinates */
>> +	DRM_DEBUG_DRIVER("Layer coordinates X: %d Y: %d\n",
>> +			 state->crtc_x, state->crtc_y);
>> +	regmap_write(mixer->regs, SUN8I_MIXER_CHAN_UI_LAYER_COORD(chan,
>layer),
>> +		     SUN8I_MIXER_COORD(state->crtc_x, state->crtc_y));
>> +
>> +	return 0;
>> +}
>> +EXPORT_SYMBOL(sun8i_mixer_update_layer_coord);
>> +
>> +int sun8i_mixer_update_layer_formats(struct sun8i_mixer *mixer,
>> +				       int layer, struct drm_plane *plane)
>> +{
>> +	struct drm_plane_state *state = plane->state;
>> +	struct drm_framebuffer *fb = state->fb;
>> +	bool interlaced = false;
>> +	u32 val;
>> +	/* Currently the first UI channel is used */
>> +	int chan = mixer->cfg->vi_num;
>> +	int ret;
>> +
>> +	if (plane->state->crtc)
>> +		interlaced = plane->state->crtc->state->adjusted_mode.flags
>> +			& DRM_MODE_FLAG_INTERLACE;
>> +
>> +	regmap_update_bits(mixer->regs, SUN8I_MIXER_BLEND_OUTCTL,
>> +			   SUN8I_MIXER_BLEND_OUTCTL_INTERLACED,
>> +			   interlaced ?
>> +			   SUN8I_MIXER_BLEND_OUTCTL_INTERLACED : 0);
>> +
>> +	DRM_DEBUG_DRIVER("Switching display mixer interlaced mode %s\n",
>> +			 interlaced ? "on" : "off");
>
>You're not using interlaced anywhere.

ok.

>
>> +
>> +	ret = sun8i_mixer_drm_format_to_layer(plane, fb->format->format,
>> +						&val);
>> +	if (ret) {
>> +		DRM_DEBUG_DRIVER("Invalid format\n");
>> +		return ret;
>> +	}
>> +
>> +	regmap_update_bits(mixer->regs,
>> +			   SUN8I_MIXER_CHAN_UI_LAYER_ATTR(chan, layer),
>> +			   SUN8I_MIXER_CHAN_UI_LAYER_ATTR_FBFMT_MASK, val);
>> +
>> +	return 0;
>> +}
>> +EXPORT_SYMBOL(sun8i_mixer_update_layer_formats);
>> +
>> +int sun8i_mixer_update_layer_buffer(struct sun8i_mixer *mixer,
>> +				      int layer, struct drm_plane *plane)
>> +{
>> +	struct drm_plane_state *state = plane->state;
>> +	struct drm_framebuffer *fb = state->fb;
>> +	struct drm_gem_cma_object *gem;
>> +	dma_addr_t paddr;
>> +	uint32_t paddr_u32;
>> +	/* Currently the first UI channel is used */
>> +	int chan = mixer->cfg->vi_num;
>> +	int bpp;
>> +
>> +	/* Get the physical address of the buffer in memory */
>> +	gem = drm_fb_cma_get_gem_obj(fb, 0);
>> +
>> +	DRM_DEBUG_DRIVER("Using GEM @ %pad\n", &gem->paddr);
>> +
>> +	/* Compute the start of the displayed memory */
>> +	bpp = fb->format->cpp[0];
>> +	paddr = gem->paddr + fb->offsets[0];
>> +	paddr += (state->src_x >> 16) * bpp;
>> +	paddr += (state->src_y >> 16) * fb->pitches[0];
>> +
>> +	DRM_DEBUG_DRIVER("Setting buffer address to %pad\n", &paddr);
>> +
>> +	paddr_u32 = (uint32_t) paddr;
>
>How does that work on 64-bits systems ?

The hardware is not designed to work on 64-bit systems.

Even 64-bit A64/H5 has also 3GiB memory limit.

The address cell in mixer hardware is also only 32-bit.

So we should just keep the force conversion here. If we then really met 4GiB-capable AW SoC without changing DE2, I think we should have other way to limit CMA pool inside 4GiB.

>
>> +
>> +	regmap_write(mixer->regs,
>> +		     SUN8I_MIXER_CHAN_UI_LAYER_TOP_LADDR(chan, layer),
>> +		     paddr_u32);
>> +
>> +	return 0;
>> +}
>> +EXPORT_SYMBOL(sun8i_mixer_update_layer_buffer);
>> +
>> +static const struct sunxi_engine_ops sun8i_engine_ops = {
>> +	.commit = sun8i_mixer_commit,
>> +	.layers_init = sun8i_layers_init,
>
>Align with tabs.
>
>> +};
>> +
>> +static struct regmap_config sun8i_mixer_regmap_config = {
>> +	.reg_bits	= 32,
>> +	.val_bits	= 32,
>> +	.reg_stride	= 4,
>> +	.max_register	= 0xbfffc, /* guessed */
>> +};
>> +
>> +static int sun8i_mixer_bind(struct device *dev, struct device
>*master,
>> +			      void *data)
>> +{
>> +	struct platform_device *pdev = to_platform_device(dev);
>> +	struct drm_device *drm = data;
>> +	struct sun4i_drv *drv = drm->dev_private;
>> +	struct sun8i_mixer *mixer;
>> +	struct resource *res;
>> +	void __iomem *regs;
>> +	int i, ret;
>> +
>> +	mixer = devm_kzalloc(dev, sizeof(*mixer), GFP_KERNEL);
>> +	if (!mixer)
>> +		return -ENOMEM;
>> +	dev_set_drvdata(dev, mixer);
>> +	drv->engine = mixer;
>> +	drv->engine_ops = &sun8i_engine_ops;
>> +
>> +	mixer->cfg = of_device_get_match_data(dev);
>> +	if (!mixer->cfg)
>> +		return -EINVAL;
>> +
>> +	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
>> +	regs = devm_ioremap_resource(dev, res);
>> +	if (IS_ERR(regs))
>> +		return PTR_ERR(regs);
>> +
>> +	mixer->regs = devm_regmap_init_mmio(dev, regs,
>> +					      &sun8i_mixer_regmap_config);
>> +	if (IS_ERR(mixer->regs)) {
>> +		dev_err(dev, "Couldn't create the mixer regmap\n");
>> +		return PTR_ERR(mixer->regs);
>> +	}
>> +
>> +	mixer->reset = devm_reset_control_get(dev, NULL);
>> +	if (IS_ERR(mixer->reset)) {
>> +		dev_err(dev, "Couldn't get our reset line\n");
>> +		return PTR_ERR(mixer->reset);
>> +	}
>> +
>> +	ret = reset_control_deassert(mixer->reset);
>> +	if (ret) {
>> +		dev_err(dev, "Couldn't deassert our reset line\n");
>> +		return ret;
>> +	}
>> +
>> +	mixer->bus_clk = devm_clk_get(dev, "bus");
>> +	if (IS_ERR(mixer->bus_clk)) {
>> +		dev_err(dev, "Couldn't get the mixer bus clock\n");
>> +		ret = PTR_ERR(mixer->bus_clk);
>> +		goto err_assert_reset;
>> +	}
>> +	clk_prepare_enable(mixer->bus_clk);
>> +
>> +	mixer->mod_clk = devm_clk_get(dev, "mod");
>> +	if (IS_ERR(mixer->mod_clk)) {
>> +		dev_err(dev, "Couldn't get the mixer module clock\n");
>> +		ret = PTR_ERR(mixer->mod_clk);
>> +		goto err_disable_bus_clk;
>> +	}
>> +	clk_prepare_enable(mixer->mod_clk);
>> +
>> +	/* Reset the registers */
>> +	for (i = 0x0; i < 0x20000; i += 4)
>> +		regmap_write(mixer->regs, i, 0);
>> +
>> +	/* Enable the mixer */
>> +	regmap_write(mixer->regs, SUN8I_MIXER_GLOBAL_CTL,
>> +		     SUN8I_MIXER_GLOBAL_CTL_RT_EN);
>> +
>> +	/* Initialize blender */
>> +	regmap_write(mixer->regs, SUN8I_MIXER_BLEND_FCOLOR_CTL,
>> +		     SUN8I_MIXER_BLEND_FCOLOR_CTL_DEF);
>> +	regmap_write(mixer->regs, SUN8I_MIXER_BLEND_PREMULTIPLY,
>> +		     SUN8I_MIXER_BLEND_PREMULTIPLY_DEF);
>> +	regmap_write(mixer->regs, SUN8I_MIXER_BLEND_BKCOLOR,
>> +		     SUN8I_MIXER_BLEND_BKCOLOR_DEF);
>> +	regmap_write(mixer->regs, SUN8I_MIXER_BLEND_MODE(0),
>> +		     SUN8I_MIXER_BLEND_MODE_DEF);
>> +	regmap_write(mixer->regs, SUN8I_MIXER_BLEND_CK_CTL,
>> +		     SUN8I_MIXER_BLEND_CK_CTL_DEF);
>> +
>> +	regmap_write(mixer->regs,
>> +		     SUN8I_MIXER_BLEND_ATTR_FCOLOR(0),
>> +		     SUN8I_MIXER_BLEND_ATTR_FCOLOR_DEF);
>> +
>> +	/* Select the first UI channel */
>> +	DRM_DEBUG_DRIVER("Selecting channel %d (first UI channel)\n",
>> +			 mixer->cfg->vi_num);
>> +	regmap_write(mixer->regs, SUN8I_MIXER_BLEND_ROUTE,
>> +		     mixer->cfg->vi_num);
>> +
>> +	return 0;
>> +
>> +	clk_disable_unprepare(mixer->mod_clk);
>> +err_disable_bus_clk:
>> +	clk_disable_unprepare(mixer->bus_clk);
>> +err_assert_reset:
>> +	reset_control_assert(mixer->reset);
>> +	return ret;
>> +}
>> +
>> +static void sun8i_mixer_unbind(struct device *dev, struct device
>*master,
>> +				 void *data)
>> +{
>> +	struct sun8i_mixer *mixer = dev_get_drvdata(dev);
>> +
>> +	clk_disable_unprepare(mixer->mod_clk);
>> +	clk_disable_unprepare(mixer->bus_clk);
>> +	reset_control_assert(mixer->reset);
>> +}
>> +
>> +static const struct component_ops sun8i_mixer_ops = {
>> +	.bind	= sun8i_mixer_bind,
>> +	.unbind	= sun8i_mixer_unbind,
>> +};
>> +
>> +static int sun8i_mixer_probe(struct platform_device *pdev)
>> +{
>> +	return component_add(&pdev->dev, &sun8i_mixer_ops);
>> +}
>> +
>> +static int sun8i_mixer_remove(struct platform_device *pdev)
>> +{
>> +	component_del(&pdev->dev, &sun8i_mixer_ops);
>> +
>> +	return 0;
>> +}
>> +
>> +static const struct sun8i_mixer_cfg sun8i_v3s_mixer_cfg = {
>> +	.vi_num = 2,
>> +	.ui_num = 1,
>> +};
>> +
>> +static const struct of_device_id sun8i_mixer_of_table[] = {
>> +	{
>> +		.compatible = "allwinner,sun8i-v3s-de2-mixer",
>> +		.data = &sun8i_v3s_mixer_cfg,
>> +	},
>> +	{ }
>> +};
>> +MODULE_DEVICE_TABLE(of, sun8i_mixer_of_table);
>> +
>> +static struct platform_driver sun8i_mixer_platform_driver = {
>> +	.probe		= sun8i_mixer_probe,
>> +	.remove		= sun8i_mixer_remove,
>> +	.driver		= {
>> +		.name		= "sun8i-mixer",
>> +		.of_match_table	= sun8i_mixer_of_table,
>> +	},
>> +};
>> +module_platform_driver(sun8i_mixer_platform_driver);
>> +
>> +MODULE_AUTHOR("Icenowy Zheng <icenowy-h8G6r0blFSE@public.gmane.org>");
>> +MODULE_DESCRIPTION("Allwinner DE2 Mixer driver");
>> +MODULE_LICENSE("GPL");
>> diff --git a/drivers/gpu/drm/sun4i/sun8i_mixer.h
>b/drivers/gpu/drm/sun4i/sun8i_mixer.h
>> new file mode 100644
>> index 000000000000..a4a365ae44c9
>> --- /dev/null
>> +++ b/drivers/gpu/drm/sun4i/sun8i_mixer.h
>> @@ -0,0 +1,131 @@
>> +/*
>> + * Copyright (C) 2017 Icenowy Zheng <icenowy-h8G6r0blFSE@public.gmane.org>
>> + *
>> + * This program is free software; you can redistribute it and/or
>> + * modify it under the terms of the GNU General Public License as
>> + * published by the Free Software Foundation; either version 2 of
>> + * the License, or (at your option) any later version.
>> + */
>> +
>> +#ifndef _SUN8I_MIXER_H_
>> +#define _SUN8I_MIXER_H_
>> +
>> +#include <linux/clk.h>
>> +#include <linux/regmap.h>
>> +#include <linux/reset.h>
>> +
>> +#include "sun4i_layer.h"
>> +
>> +#define SUN8I_MIXER_MAX_CHAN_COUNT		4
>> +
>> +#define SUN8I_MIXER_SIZE(w, h)			(((h) - 1) << 16 | ((w) - 1))
>> +#define SUN8I_MIXER_COORD(x, y)			((y) << 16 | (x))
>> +
>> +#define SUN8I_MIXER_GLOBAL_CTL			0x0
>> +#define SUN8I_MIXER_GLOBAL_STATUS		0x4
>> +#define SUN8I_MIXER_GLOBAL_DBUFF		0x8
>> +#define SUN8I_MIXER_GLOBAL_SIZE			0xc
>> +
>> +#define SUN8I_MIXER_GLOBAL_CTL_RT_EN		0x1
>> +
>> +#define SUN8I_MIXER_GLOBAL_DBUFF_ENABLE		0x1
>> +
>> +#define SUN8I_MIXER_BLEND_FCOLOR_CTL		0x1000
>> +#define SUN8I_MIXER_BLEND_ATTR_FCOLOR(x)	(0x1004 + 0x10 * (x) + 0x0)
>> +#define SUN8I_MIXER_BLEND_ATTR_INSIZE(x)	(0x1004 + 0x10 * (x) + 0x4)
>> +#define SUN8I_MIXER_BLEND_ATTR_OFFSET(x)	(0x1004 + 0x10 * (x) + 0x8)
>> +#define SUN8I_MIXER_BLEND_ROUTE			0x1080
>> +#define SUN8I_MIXER_BLEND_PREMULTIPLY		0x1084
>> +#define SUN8I_MIXER_BLEND_BKCOLOR		0x1088
>> +#define SUN8I_MIXER_BLEND_OUTSIZE		0x108c
>> +#define SUN8I_MIXER_BLEND_MODE(x)		(0x1090 + 0x04 * (x))
>> +#define SUN8I_MIXER_BLEND_CK_CTL		0x10b0
>> +#define SUN8I_MIXER_BLEND_CK_CFG		0x10b4
>> +#define SUN8I_MIXER_BLEND_CK_MAX(x)		(0x10c0 + 0x04 * (x))
>> +#define SUN8I_MIXER_BLEND_CK_MIN(x)		(0x10e0 + 0x04 * (x))
>> +#define SUN8I_MIXER_BLEND_OUTCTL		0x10fc
>> +
>> +/* The following numbers are some still unknown magic numbers */
>> +#define SUN8I_MIXER_BLEND_ATTR_FCOLOR_DEF	0xff000000
>> +#define SUN8I_MIXER_BLEND_FCOLOR_CTL_DEF	0x00000101
>> +#define SUN8I_MIXER_BLEND_PREMULTIPLY_DEF	0x0
>> +#define SUN8I_MIXER_BLEND_BKCOLOR_DEF		0xff000000
>> +#define SUN8I_MIXER_BLEND_MODE_DEF		0x03010301
>> +#define SUN8I_MIXER_BLEND_CK_CTL_DEF		0x0
>> +
>> +#define SUN8I_MIXER_BLEND_OUTCTL_INTERLACED	BIT(1)
>> +
>> +/*
>> + * VI channels are not used now, but the support of them may be
>introduced in
>> + * the future.
>> + */
>> +
>> +#define SUN8I_MIXER_CHAN_UI_LAYER_ATTR(ch, layer) \
>> +			(0x2000 + 0x1000 * (ch) + 0x20 * (layer) + 0x0)
>> +#define SUN8I_MIXER_CHAN_UI_LAYER_SIZE(ch, layer) \
>> +			(0x2000 + 0x1000 * (ch) + 0x20 * (layer) + 0x4)
>> +#define SUN8I_MIXER_CHAN_UI_LAYER_COORD(ch, layer) \
>> +			(0x2000 + 0x1000 * (ch) + 0x20 * (layer) + 0x8)
>> +#define SUN8I_MIXER_CHAN_UI_LAYER_PITCH(ch, layer) \
>> +			(0x2000 + 0x1000 * (ch) + 0x20 * (layer) + 0xc)
>> +#define SUN8I_MIXER_CHAN_UI_LAYER_TOP_LADDR(ch, layer) \
>> +			(0x2000 + 0x1000 * (ch) + 0x20 * (layer) + 0x10)
>> +#define SUN8I_MIXER_CHAN_UI_LAYER_BOT_LADDR(ch, layer) \
>> +			(0x2000 + 0x1000 * (ch) + 0x20 * (layer) + 0x14)
>> +#define SUN8I_MIXER_CHAN_UI_LAYER_FCOLOR(ch, layer) \
>> +			(0x2000 + 0x1000 * (ch) + 0x20 * (layer) + 0x18)
>> +#define SUN8I_MIXER_CHAN_UI_TOP_HADDR(ch)	(0x2000 + 0x1000 * (ch) +
>0x80)
>> +#define SUN8I_MIXER_CHAN_UI_BOT_HADDR(ch)	(0x2000 + 0x1000 * (ch) +
>0x84)
>> +#define SUN8I_MIXER_CHAN_UI_OVL_SIZE(ch)	(0x2000 + 0x1000 * (ch) +
>0x88)
>> +
>> +#define SUN8I_MIXER_CHAN_UI_LAYER_ATTR_EN		BIT(0)
>> +#define SUN8I_MIXER_CHAN_UI_LAYER_ATTR_ALPHA_MODE_MASK	GENMASK(2, 1)
>> +#define SUN8I_MIXER_CHAN_UI_LAYER_ATTR_FBFMT_MASK	GENMASK(11, 8)
>> +#define SUN8I_MIXER_CHAN_UI_LAYER_ATTR_ALPHA_MASK	GENMASK(31, 24)
>> +#define SUN8I_MIXER_CHAN_UI_LAYER_ATTR_ALPHA_MODE_DEF	(1 << 1)
>> +#define SUN8I_MIXER_CHAN_UI_LAYER_ATTR_FBFMT_ARGB8888	(0 << 8)
>> +#define SUN8I_MIXER_CHAN_UI_LAYER_ATTR_FBFMT_XRGB8888	(4 << 8)
>> +#define SUN8I_MIXER_CHAN_UI_LAYER_ATTR_FBFMT_RGB888	(8 << 8)
>> +#define SUN8I_MIXER_CHAN_UI_LAYER_ATTR_ALPHA_DEF	(0xff << 24)
>> +
>> +/*
>> + * These sub-engines are still unknown now, the EN registers are
>here only to
>> + * be used to disable these sub-engines.
>> + */
>> +#define SUN8I_MIXER_VSU_EN			0x20000
>> +#define SUN8I_MIXER_GSU1_EN			0x30000
>> +#define SUN8I_MIXER_GSU2_EN			0x40000
>> +#define SUN8I_MIXER_GSU3_EN			0x50000
>> +#define SUN8I_MIXER_FCE_EN			0xa0000
>> +#define SUN8I_MIXER_BWS_EN			0xa2000
>> +#define SUN8I_MIXER_LTI_EN			0xa4000
>> +#define SUN8I_MIXER_PEAK_EN			0xa6000
>> +#define SUN8I_MIXER_ASE_EN			0xa8000
>> +#define SUN8I_MIXER_FCC_EN			0xaa000
>> +#define SUN8I_MIXER_DCSC_EN			0xb0000
>> +
>> +struct sun8i_mixer_cfg {
>> +	int		vi_num;
>> +	int		ui_num;
>> +};
>> +
>> +struct sun8i_mixer {
>> +	struct regmap			*regs;
>> +
>> +	const struct sun8i_mixer_cfg	*cfg;
>> +
>> +	struct reset_control		*reset;
>> +
>> +	struct clk			*bus_clk;
>> +	struct clk			*mod_clk;
>> +};
>> +
>> +void sun8i_mixer_layer_enable(struct sun8i_mixer *mixer,
>> +				int layer, bool enable);
>> +int sun8i_mixer_update_layer_coord(struct sun8i_mixer *mixer,
>> +				     int layer, struct drm_plane *plane);
>> +int sun8i_mixer_update_layer_formats(struct sun8i_mixer *mixer,
>> +				       int layer, struct drm_plane *plane);
>> +int sun8i_mixer_update_layer_buffer(struct sun8i_mixer *mixer,
>> +				      int layer, struct drm_plane *plane);
>> +#endif /* _SUN8I_MIXER_H_ */
>
>Thanks,
>Maxime

-- 
You received this message because you are subscribed to the Google Groups "linux-sunxi" group.
To unsubscribe from this group and stop receiving emails from it, send an email to linux-sunxi+unsubscribe-/JYPxA39Uh5TLH3MbocFF+G/Ez6ZCGd0@public.gmane.org
For more options, visit https://groups.google.com/d/optout.

WARNING: multiple messages have this Message-ID (diff)
From: icenowy@aosc.io (Icenowy Zheng)
To: linux-arm-kernel@lists.infradead.org
Subject: [PATCH v4 06/11] drm/sun4i: add support for Allwinner DE2 mixers
Date: Tue, 18 Apr 2017 18:47:56 +0800	[thread overview]
Message-ID: <88F5FAC9-1873-4C76-9AB9-FF361C07664E@aosc.io> (raw)
In-Reply-To: <20170418090047.7i2k6dtoqxfdqwwy@lukather>



? 2017?4?18? GMT+08:00 ??5:00:47, Maxime Ripard <maxime.ripard@free-electrons.com> ??:
>On Sun, Apr 16, 2017 at 08:08:44PM +0800, Icenowy Zheng wrote:
>> Allwinner have a new "Display Engine 2.0" in their new SoCs, which
>comes
>> with mixers to do graphic processing and feed data to TCON, like the
>old
>> backends and frontends.
>> 
>> Add support for the mixer on Allwinner V3s SoC; it's the simplest
>one.
>> 
>> Currently a lot of functions are still missing -- more investigations
>> are needed to gain enough information for them.
>> 
>> Signed-off-by: Icenowy Zheng <icenowy@aosc.io>
>> ---
>> Changes in v4:
>> - Killed some dead code according to Jernej.
>> 
>>  drivers/gpu/drm/sun4i/Kconfig       |  10 +
>>  drivers/gpu/drm/sun4i/Makefile      |   4 +
>>  drivers/gpu/drm/sun4i/sun8i_layer.c | 142 ++++++++++++++
>>  drivers/gpu/drm/sun4i/sun8i_layer.h |  36 ++++
>>  drivers/gpu/drm/sun4i/sun8i_mixer.c | 381
>++++++++++++++++++++++++++++++++++++
>>  drivers/gpu/drm/sun4i/sun8i_mixer.h | 131 +++++++++++++
>>  6 files changed, 704 insertions(+)
>>  create mode 100644 drivers/gpu/drm/sun4i/sun8i_layer.c
>>  create mode 100644 drivers/gpu/drm/sun4i/sun8i_layer.h
>>  create mode 100644 drivers/gpu/drm/sun4i/sun8i_mixer.c
>>  create mode 100644 drivers/gpu/drm/sun4i/sun8i_mixer.h
>> 
>> diff --git a/drivers/gpu/drm/sun4i/Kconfig
>b/drivers/gpu/drm/sun4i/Kconfig
>> index 5a8227f37cc4..15557484520d 100644
>> --- a/drivers/gpu/drm/sun4i/Kconfig
>> +++ b/drivers/gpu/drm/sun4i/Kconfig
>> @@ -22,3 +22,13 @@ config DRM_SUN4I_BACKEND
>>  	  original Allwinner Display Engine, which has a backend to
>>  	  do some alpha blending and feed graphics to TCON. If M is
>>  	  selected the module will be called sun4i-backend.
>> +
>> +config DRM_SUN4I_SUN8I_MIXER
>> +	tristate "Support for Allwinner Display Engine 2.0 Mixer"
>> +	depends on DRM_SUN4I
>> +	default MACH_SUN8I
>> +	help
>> +	  Choose this option if you have an Allwinner SoC with the
>> +	  Allwinner Display Engine 2.0, which has a mixer to do some
>> +	  graphics mixture and feed graphics to TCON, If M is
>> +	  selected the module will be called sun8i-mixer.
>> diff --git a/drivers/gpu/drm/sun4i/Makefile
>b/drivers/gpu/drm/sun4i/Makefile
>> index 1db1068b9be1..7625c2dad1bb 100644
>> --- a/drivers/gpu/drm/sun4i/Makefile
>> +++ b/drivers/gpu/drm/sun4i/Makefile
>> @@ -9,7 +9,11 @@ sun4i-tcon-y += sun4i_crtc.o
>>  sun4i-backend-y += sun4i_layer.o
>>  sun4i-backend-y += sun4i_backend.o
>>  
>> +sun8i-mixer-y += sun8i_layer.o
>> +sun8i-mixer-y += sun8i_mixer.o
>> +
>>  obj-$(CONFIG_DRM_SUN4I)		+= sun4i-drm.o sun4i-tcon.o
>>  obj-$(CONFIG_DRM_SUN4I_BACKEND)	+= sun4i-backend.o
>> +obj-$(CONFIG_DRM_SUN4I_SUN8I_MIXER) += sun8i-mixer.o
>
>Please align the value using tabs.

Should I re-align existed items?

>
>>  obj-$(CONFIG_DRM_SUN4I)		+= sun6i_drc.o
>>  obj-$(CONFIG_DRM_SUN4I)		+= sun4i_tv.o
>> diff --git a/drivers/gpu/drm/sun4i/sun8i_layer.c
>b/drivers/gpu/drm/sun4i/sun8i_layer.c
>> new file mode 100644
>> index 000000000000..d70a90d963b0
>> --- /dev/null
>> +++ b/drivers/gpu/drm/sun4i/sun8i_layer.c
>> @@ -0,0 +1,142 @@
>> +/*
>> + * Copyright (C) Icenowy Zheng <icenowy@aosc.io>
>> + *
>> + * Based on sun4i_layer.h, which is:
>> + *   Copyright (C) 2015 Free Electrons
>> + *   Copyright (C) 2015 NextThing Co
>> + *
>> + *   Maxime Ripard <maxime.ripard@free-electrons.com>
>> + *
>> + * This program is free software; you can redistribute it and/or
>> + * modify it under the terms of the GNU General Public License as
>> + * published by the Free Software Foundation; either version 2 of
>> + * the License, or (at your option) any later version.
>> + */
>> +
>> +#include <drm/drm_atomic_helper.h>
>> +#include <drm/drm_crtc.h>
>> +#include <drm/drm_plane_helper.h>
>> +#include <drm/drmP.h>
>> +
>> +#include "sun4i_crtc.h"
>> +#include "sun8i_layer.h"
>> +#include "sun8i_mixer.h"
>> +
>> +struct sun8i_plane_desc {
>> +	       enum drm_plane_type     type;
>> +	       const uint32_t          *formats;
>> +	       uint32_t                nformats;
>> +};
>> +
>> +static int sun8i_mixer_layer_atomic_check(struct drm_plane *plane,
>> +					    struct drm_plane_state *state)
>> +{
>> +	return 0;
>> +}
>> +
>> +static void sun8i_mixer_layer_atomic_disable(struct drm_plane
>*plane,
>> +					       struct drm_plane_state *old_state)
>> +{
>> +	struct sun8i_layer *layer = plane_to_sun8i_layer(plane);
>> +	struct sun8i_mixer *mixer = layer->mixer;
>> +
>> +	sun8i_mixer_layer_enable(mixer, layer->id, false);
>> +}
>> +
>> +static void sun8i_mixer_layer_atomic_update(struct drm_plane *plane,
>> +					      struct drm_plane_state *old_state)
>> +{
>> +	struct sun8i_layer *layer = plane_to_sun8i_layer(plane);
>> +	struct sun8i_mixer *mixer = layer->mixer;
>> +
>> +	sun8i_mixer_update_layer_coord(mixer, layer->id, plane);
>> +	sun8i_mixer_update_layer_formats(mixer, layer->id, plane);
>> +	sun8i_mixer_update_layer_buffer(mixer, layer->id, plane);
>> +	sun8i_mixer_layer_enable(mixer, layer->id, true);
>> +}
>> +
>> +static struct drm_plane_helper_funcs sun8i_mixer_layer_helper_funcs
>= {
>> +	.atomic_check	= sun8i_mixer_layer_atomic_check,
>> +	.atomic_disable	= sun8i_mixer_layer_atomic_disable,
>> +	.atomic_update	= sun8i_mixer_layer_atomic_update,
>> +};
>> +
>> +static const struct drm_plane_funcs sun8i_mixer_layer_funcs = {
>> +	.atomic_destroy_state	= drm_atomic_helper_plane_destroy_state,
>> +	.atomic_duplicate_state	= drm_atomic_helper_plane_duplicate_state,
>> +	.destroy		= drm_plane_cleanup,
>> +	.disable_plane		= drm_atomic_helper_disable_plane,
>> +	.reset			= drm_atomic_helper_plane_reset,
>> +	.update_plane		= drm_atomic_helper_update_plane,
>> +};
>> +
>> +static const uint32_t sun8i_mixer_layer_formats[] = {
>> +	DRM_FORMAT_RGB888,
>> +	DRM_FORMAT_XRGB8888,
>> +};
>> +
>> +static const struct sun8i_plane_desc sun8i_mixer_planes[] = {
>> +	{
>> +		.type = DRM_PLANE_TYPE_PRIMARY,
>> +		.formats = sun8i_mixer_layer_formats,
>> +		.nformats = ARRAY_SIZE(sun8i_mixer_layer_formats),
>> +	},
>> +};
>> +
>> +static struct sun8i_layer *sun8i_layer_init_one(struct drm_device
>*drm,
>> +						struct sun8i_mixer *mixer,
>> +						const struct sun8i_plane_desc *plane)
>> +{
>> +	struct sun8i_layer *layer;
>> +	int ret;
>> +
>> +	layer = devm_kzalloc(drm->dev, sizeof(*layer), GFP_KERNEL);
>> +	if (!layer)
>> +		return ERR_PTR(-ENOMEM);
>> +
>> +	/* possible crtcs are set later */
>> +	ret = drm_universal_plane_init(drm, &layer->plane, 0,
>> +				       &sun8i_mixer_layer_funcs,
>> +				       plane->formats, plane->nformats,
>> +				       plane->type, NULL);
>> +	if (ret) {
>> +		dev_err(drm->dev, "Couldn't initialize layer\n");
>> +		return ERR_PTR(ret);
>> +	}
>> +
>> +	drm_plane_helper_add(&layer->plane,
>> +			     &sun8i_mixer_layer_helper_funcs);
>> +	layer->mixer = mixer;
>> +
>> +	return layer;
>> +}
>> +
>> +struct drm_plane **sun8i_layers_init(struct drm_device *drm,
>> +				     struct sun4i_crtc *crtc)
>> +{
>> +	struct drm_plane **planes;
>> +	struct sun8i_mixer *mixer = crtc->engine;
>> +	int i;
>> +
>> +	planes = devm_kcalloc(drm->dev, ARRAY_SIZE(sun8i_mixer_planes) + 1,
>> +			      sizeof(*planes), GFP_KERNEL);
>> +	if (!planes)
>> +		return ERR_PTR(-ENOMEM);
>> +
>> +	for (i = 0; i < ARRAY_SIZE(sun8i_mixer_planes); i++) {
>> +		const struct sun8i_plane_desc *plane = &sun8i_mixer_planes[i];
>> +		struct sun8i_layer *layer;
>> +
>> +		layer = sun8i_layer_init_one(drm, mixer, plane);
>> +		if (IS_ERR(layer)) {
>> +			dev_err(drm->dev, "Couldn't initialize %s plane\n",
>> +				i ? "overlay" : "primary");
>> +			return ERR_CAST(layer);
>> +		};
>> +
>> +		layer->id = i;
>> +		planes[i] = &layer->plane;
>> +	};
>> +
>> +	return planes;
>> +}
>> diff --git a/drivers/gpu/drm/sun4i/sun8i_layer.h
>b/drivers/gpu/drm/sun4i/sun8i_layer.h
>> new file mode 100644
>> index 000000000000..fe7e8a069d71
>> --- /dev/null
>> +++ b/drivers/gpu/drm/sun4i/sun8i_layer.h
>> @@ -0,0 +1,36 @@
>> +/*
>> + * Copyright (C) Icenowy Zheng <icenowy@aosc.io>
>> + *
>> + * Based on sun4i_layer.h, which is:
>> + *   Copyright (C) 2015 Free Electrons
>> + *   Copyright (C) 2015 NextThing Co
>> + *
>> + *   Maxime Ripard <maxime.ripard@free-electrons.com>
>> + *
>> + * This program is free software; you can redistribute it and/or
>> + * modify it under the terms of the GNU General Public License as
>> + * published by the Free Software Foundation; either version 2 of
>> + * the License, or (at your option) any later version.
>> + */
>> +
>> +#ifndef _SUN8I_LAYER_H_
>> +#define _SUN8I_LAYER_H_
>> +
>> +struct sun4i_crtc;
>> +
>> +struct sun8i_layer {
>> +	struct drm_plane	plane;
>> +	struct sun4i_drv	*drv;
>> +	struct sun8i_mixer	*mixer;
>> +	int			id;
>> +};
>> +
>> +static inline struct sun8i_layer *
>> +plane_to_sun8i_layer(struct drm_plane *plane)
>> +{
>> +	return container_of(plane, struct sun8i_layer, plane);
>> +}
>> +
>> +struct drm_plane **sun8i_layers_init(struct drm_device *drm,
>> +				     struct sun4i_crtc *crtc);
>> +#endif /* _SUN8I_LAYER_H_ */
>> diff --git a/drivers/gpu/drm/sun4i/sun8i_mixer.c
>b/drivers/gpu/drm/sun4i/sun8i_mixer.c
>> new file mode 100644
>> index 000000000000..5cff3f3833a7
>> --- /dev/null
>> +++ b/drivers/gpu/drm/sun4i/sun8i_mixer.c
>> @@ -0,0 +1,381 @@
>> +/*
>> + * Copyright (C) 2017 Icenowy Zheng <icenowy@aosc.io>
>> + *
>> + * Based on sun4i_backend.c, which is:
>> + *   Copyright (C) 2015 Free Electrons
>> + *   Copyright (C) 2015 NextThing Co
>> + *
>> + * This program is free software; you can redistribute it and/or
>> + * modify it under the terms of the GNU General Public License as
>> + * published by the Free Software Foundation; either version 2 of
>> + * the License, or (at your option) any later version.
>> + */
>> +
>> +#include <drm/drmP.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_gem_cma_helper.h>
>> +#include <drm/drm_plane_helper.h>
>> +
>> +#include <linux/component.h>
>> +#include <linux/reset.h>
>> +#include <linux/of_device.h>
>> +
>> +#include "sun4i_drv.h"
>> +#include "sun8i_mixer.h"
>> +#include "sun8i_layer.h"
>> +#include "sunxi_engine.h"
>> +
>> +void sun8i_mixer_commit(void *mixer)
>> +{
>> +	struct sun8i_mixer *sun8i_mixer = mixer;
>> +
>> +	DRM_DEBUG_DRIVER("Committing changes\n");
>> +
>> +	regmap_write(sun8i_mixer->regs, SUN8I_MIXER_GLOBAL_DBUFF,
>> +		     SUN8I_MIXER_GLOBAL_DBUFF_ENABLE);
>> +}
>> +
>> +void sun8i_mixer_layer_enable(struct sun8i_mixer *mixer,
>> +				int layer, bool enable)
>> +{
>> +	u32 val;
>> +	/* Currently the first UI channel is used */
>> +	int chan = mixer->cfg->vi_num;
>> +
>> +	DRM_DEBUG_DRIVER("Enabling layer %d in channel %d\n", layer, chan);
>> +
>> +	if (enable)
>> +		val = SUN8I_MIXER_CHAN_UI_LAYER_ATTR_EN;
>> +	else
>> +		val = 0;
>> +
>> +	regmap_update_bits(mixer->regs,
>> +			   SUN8I_MIXER_CHAN_UI_LAYER_ATTR(chan, layer),
>> +			   SUN8I_MIXER_CHAN_UI_LAYER_ATTR_EN, val);
>> +
>> +	/* Set the alpha configuration */
>> +	regmap_update_bits(mixer->regs,
>> +			   SUN8I_MIXER_CHAN_UI_LAYER_ATTR(chan, layer),
>> +			   SUN8I_MIXER_CHAN_UI_LAYER_ATTR_ALPHA_MODE_MASK,
>> +			   SUN8I_MIXER_CHAN_UI_LAYER_ATTR_ALPHA_MODE_DEF);
>> +	regmap_update_bits(mixer->regs,
>> +			   SUN8I_MIXER_CHAN_UI_LAYER_ATTR(chan, layer),
>> +			   SUN8I_MIXER_CHAN_UI_LAYER_ATTR_ALPHA_MASK,
>> +			   SUN8I_MIXER_CHAN_UI_LAYER_ATTR_ALPHA_DEF);
>> +}
>> +EXPORT_SYMBOL(sun8i_mixer_layer_enable);
>
>Why do you need to export it?

Oh... not needed. This export is dead code.

>
>> +
>> +static int sun8i_mixer_drm_format_to_layer(struct drm_plane *plane,
>> +					     u32 format, u32 *mode)
>> +{
>> +	switch (format) {
>> +	case DRM_FORMAT_XRGB8888:
>> +		*mode = SUN8I_MIXER_CHAN_UI_LAYER_ATTR_FBFMT_XRGB8888;
>> +		break;
>> +
>> +	case DRM_FORMAT_RGB888:
>> +		*mode = SUN8I_MIXER_CHAN_UI_LAYER_ATTR_FBFMT_RGB888;
>> +		break;
>> +
>> +	default:
>> +		return -EINVAL;
>> +	}
>> +
>> +	return 0;
>> +}
>> +
>> +int sun8i_mixer_update_layer_coord(struct sun8i_mixer *mixer,
>> +				     int layer, struct drm_plane *plane)
>> +{
>> +	struct drm_plane_state *state = plane->state;
>> +	struct drm_framebuffer *fb = state->fb;
>> +	/* Currently the first UI channel is used */
>> +	int chan = mixer->cfg->vi_num;
>> +
>> +	DRM_DEBUG_DRIVER("Updating layer %d\n", layer);
>> +
>> +	if (plane->type == DRM_PLANE_TYPE_PRIMARY) {
>> +		DRM_DEBUG_DRIVER("Primary layer, updating global size W: %u H:
>%u\n",
>> +				 state->crtc_w, state->crtc_h);
>> +		regmap_write(mixer->regs, SUN8I_MIXER_GLOBAL_SIZE,
>> +			     SUN8I_MIXER_SIZE(state->crtc_w,
>> +					      state->crtc_h));
>> +		DRM_DEBUG_DRIVER("Updating blender size\n");
>> +		regmap_write(mixer->regs,
>> +			     SUN8I_MIXER_BLEND_ATTR_INSIZE(0),
>> +			     SUN8I_MIXER_SIZE(state->crtc_w,
>> +					      state->crtc_h));
>> +		regmap_write(mixer->regs, SUN8I_MIXER_BLEND_OUTSIZE,
>> +			     SUN8I_MIXER_SIZE(state->crtc_w,
>> +					      state->crtc_h));
>> +		DRM_DEBUG_DRIVER("Updating channel size\n");
>> +		regmap_write(mixer->regs, SUN8I_MIXER_CHAN_UI_OVL_SIZE(chan),
>> +			     SUN8I_MIXER_SIZE(state->crtc_w,
>> +					      state->crtc_h));
>> +	}
>> +
>> +	/* Set the line width */
>> +	DRM_DEBUG_DRIVER("Layer line width: %d bytes\n", fb->pitches[0]);
>> +	regmap_write(mixer->regs, SUN8I_MIXER_CHAN_UI_LAYER_PITCH(chan,
>layer),
>> +		     fb->pitches[0]);
>> +
>> +	/* Set height and width */
>> +	DRM_DEBUG_DRIVER("Layer size W: %u H: %u\n",
>> +			 state->crtc_w, state->crtc_h);
>> +	regmap_write(mixer->regs, SUN8I_MIXER_CHAN_UI_LAYER_SIZE(chan,
>layer),
>> +		     SUN8I_MIXER_SIZE(state->crtc_w, state->crtc_h));
>> +
>> +	/* Set base coordinates */
>> +	DRM_DEBUG_DRIVER("Layer coordinates X: %d Y: %d\n",
>> +			 state->crtc_x, state->crtc_y);
>> +	regmap_write(mixer->regs, SUN8I_MIXER_CHAN_UI_LAYER_COORD(chan,
>layer),
>> +		     SUN8I_MIXER_COORD(state->crtc_x, state->crtc_y));
>> +
>> +	return 0;
>> +}
>> +EXPORT_SYMBOL(sun8i_mixer_update_layer_coord);
>> +
>> +int sun8i_mixer_update_layer_formats(struct sun8i_mixer *mixer,
>> +				       int layer, struct drm_plane *plane)
>> +{
>> +	struct drm_plane_state *state = plane->state;
>> +	struct drm_framebuffer *fb = state->fb;
>> +	bool interlaced = false;
>> +	u32 val;
>> +	/* Currently the first UI channel is used */
>> +	int chan = mixer->cfg->vi_num;
>> +	int ret;
>> +
>> +	if (plane->state->crtc)
>> +		interlaced = plane->state->crtc->state->adjusted_mode.flags
>> +			& DRM_MODE_FLAG_INTERLACE;
>> +
>> +	regmap_update_bits(mixer->regs, SUN8I_MIXER_BLEND_OUTCTL,
>> +			   SUN8I_MIXER_BLEND_OUTCTL_INTERLACED,
>> +			   interlaced ?
>> +			   SUN8I_MIXER_BLEND_OUTCTL_INTERLACED : 0);
>> +
>> +	DRM_DEBUG_DRIVER("Switching display mixer interlaced mode %s\n",
>> +			 interlaced ? "on" : "off");
>
>You're not using interlaced anywhere.

ok.

>
>> +
>> +	ret = sun8i_mixer_drm_format_to_layer(plane, fb->format->format,
>> +						&val);
>> +	if (ret) {
>> +		DRM_DEBUG_DRIVER("Invalid format\n");
>> +		return ret;
>> +	}
>> +
>> +	regmap_update_bits(mixer->regs,
>> +			   SUN8I_MIXER_CHAN_UI_LAYER_ATTR(chan, layer),
>> +			   SUN8I_MIXER_CHAN_UI_LAYER_ATTR_FBFMT_MASK, val);
>> +
>> +	return 0;
>> +}
>> +EXPORT_SYMBOL(sun8i_mixer_update_layer_formats);
>> +
>> +int sun8i_mixer_update_layer_buffer(struct sun8i_mixer *mixer,
>> +				      int layer, struct drm_plane *plane)
>> +{
>> +	struct drm_plane_state *state = plane->state;
>> +	struct drm_framebuffer *fb = state->fb;
>> +	struct drm_gem_cma_object *gem;
>> +	dma_addr_t paddr;
>> +	uint32_t paddr_u32;
>> +	/* Currently the first UI channel is used */
>> +	int chan = mixer->cfg->vi_num;
>> +	int bpp;
>> +
>> +	/* Get the physical address of the buffer in memory */
>> +	gem = drm_fb_cma_get_gem_obj(fb, 0);
>> +
>> +	DRM_DEBUG_DRIVER("Using GEM @ %pad\n", &gem->paddr);
>> +
>> +	/* Compute the start of the displayed memory */
>> +	bpp = fb->format->cpp[0];
>> +	paddr = gem->paddr + fb->offsets[0];
>> +	paddr += (state->src_x >> 16) * bpp;
>> +	paddr += (state->src_y >> 16) * fb->pitches[0];
>> +
>> +	DRM_DEBUG_DRIVER("Setting buffer address to %pad\n", &paddr);
>> +
>> +	paddr_u32 = (uint32_t) paddr;
>
>How does that work on 64-bits systems ?

The hardware is not designed to work on 64-bit systems.

Even 64-bit A64/H5 has also 3GiB memory limit.

The address cell in mixer hardware is also only 32-bit.

So we should just keep the force conversion here. If we then really met 4GiB-capable AW SoC without changing DE2, I think we should have other way to limit CMA pool inside 4GiB.

>
>> +
>> +	regmap_write(mixer->regs,
>> +		     SUN8I_MIXER_CHAN_UI_LAYER_TOP_LADDR(chan, layer),
>> +		     paddr_u32);
>> +
>> +	return 0;
>> +}
>> +EXPORT_SYMBOL(sun8i_mixer_update_layer_buffer);
>> +
>> +static const struct sunxi_engine_ops sun8i_engine_ops = {
>> +	.commit = sun8i_mixer_commit,
>> +	.layers_init = sun8i_layers_init,
>
>Align with tabs.
>
>> +};
>> +
>> +static struct regmap_config sun8i_mixer_regmap_config = {
>> +	.reg_bits	= 32,
>> +	.val_bits	= 32,
>> +	.reg_stride	= 4,
>> +	.max_register	= 0xbfffc, /* guessed */
>> +};
>> +
>> +static int sun8i_mixer_bind(struct device *dev, struct device
>*master,
>> +			      void *data)
>> +{
>> +	struct platform_device *pdev = to_platform_device(dev);
>> +	struct drm_device *drm = data;
>> +	struct sun4i_drv *drv = drm->dev_private;
>> +	struct sun8i_mixer *mixer;
>> +	struct resource *res;
>> +	void __iomem *regs;
>> +	int i, ret;
>> +
>> +	mixer = devm_kzalloc(dev, sizeof(*mixer), GFP_KERNEL);
>> +	if (!mixer)
>> +		return -ENOMEM;
>> +	dev_set_drvdata(dev, mixer);
>> +	drv->engine = mixer;
>> +	drv->engine_ops = &sun8i_engine_ops;
>> +
>> +	mixer->cfg = of_device_get_match_data(dev);
>> +	if (!mixer->cfg)
>> +		return -EINVAL;
>> +
>> +	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
>> +	regs = devm_ioremap_resource(dev, res);
>> +	if (IS_ERR(regs))
>> +		return PTR_ERR(regs);
>> +
>> +	mixer->regs = devm_regmap_init_mmio(dev, regs,
>> +					      &sun8i_mixer_regmap_config);
>> +	if (IS_ERR(mixer->regs)) {
>> +		dev_err(dev, "Couldn't create the mixer regmap\n");
>> +		return PTR_ERR(mixer->regs);
>> +	}
>> +
>> +	mixer->reset = devm_reset_control_get(dev, NULL);
>> +	if (IS_ERR(mixer->reset)) {
>> +		dev_err(dev, "Couldn't get our reset line\n");
>> +		return PTR_ERR(mixer->reset);
>> +	}
>> +
>> +	ret = reset_control_deassert(mixer->reset);
>> +	if (ret) {
>> +		dev_err(dev, "Couldn't deassert our reset line\n");
>> +		return ret;
>> +	}
>> +
>> +	mixer->bus_clk = devm_clk_get(dev, "bus");
>> +	if (IS_ERR(mixer->bus_clk)) {
>> +		dev_err(dev, "Couldn't get the mixer bus clock\n");
>> +		ret = PTR_ERR(mixer->bus_clk);
>> +		goto err_assert_reset;
>> +	}
>> +	clk_prepare_enable(mixer->bus_clk);
>> +
>> +	mixer->mod_clk = devm_clk_get(dev, "mod");
>> +	if (IS_ERR(mixer->mod_clk)) {
>> +		dev_err(dev, "Couldn't get the mixer module clock\n");
>> +		ret = PTR_ERR(mixer->mod_clk);
>> +		goto err_disable_bus_clk;
>> +	}
>> +	clk_prepare_enable(mixer->mod_clk);
>> +
>> +	/* Reset the registers */
>> +	for (i = 0x0; i < 0x20000; i += 4)
>> +		regmap_write(mixer->regs, i, 0);
>> +
>> +	/* Enable the mixer */
>> +	regmap_write(mixer->regs, SUN8I_MIXER_GLOBAL_CTL,
>> +		     SUN8I_MIXER_GLOBAL_CTL_RT_EN);
>> +
>> +	/* Initialize blender */
>> +	regmap_write(mixer->regs, SUN8I_MIXER_BLEND_FCOLOR_CTL,
>> +		     SUN8I_MIXER_BLEND_FCOLOR_CTL_DEF);
>> +	regmap_write(mixer->regs, SUN8I_MIXER_BLEND_PREMULTIPLY,
>> +		     SUN8I_MIXER_BLEND_PREMULTIPLY_DEF);
>> +	regmap_write(mixer->regs, SUN8I_MIXER_BLEND_BKCOLOR,
>> +		     SUN8I_MIXER_BLEND_BKCOLOR_DEF);
>> +	regmap_write(mixer->regs, SUN8I_MIXER_BLEND_MODE(0),
>> +		     SUN8I_MIXER_BLEND_MODE_DEF);
>> +	regmap_write(mixer->regs, SUN8I_MIXER_BLEND_CK_CTL,
>> +		     SUN8I_MIXER_BLEND_CK_CTL_DEF);
>> +
>> +	regmap_write(mixer->regs,
>> +		     SUN8I_MIXER_BLEND_ATTR_FCOLOR(0),
>> +		     SUN8I_MIXER_BLEND_ATTR_FCOLOR_DEF);
>> +
>> +	/* Select the first UI channel */
>> +	DRM_DEBUG_DRIVER("Selecting channel %d (first UI channel)\n",
>> +			 mixer->cfg->vi_num);
>> +	regmap_write(mixer->regs, SUN8I_MIXER_BLEND_ROUTE,
>> +		     mixer->cfg->vi_num);
>> +
>> +	return 0;
>> +
>> +	clk_disable_unprepare(mixer->mod_clk);
>> +err_disable_bus_clk:
>> +	clk_disable_unprepare(mixer->bus_clk);
>> +err_assert_reset:
>> +	reset_control_assert(mixer->reset);
>> +	return ret;
>> +}
>> +
>> +static void sun8i_mixer_unbind(struct device *dev, struct device
>*master,
>> +				 void *data)
>> +{
>> +	struct sun8i_mixer *mixer = dev_get_drvdata(dev);
>> +
>> +	clk_disable_unprepare(mixer->mod_clk);
>> +	clk_disable_unprepare(mixer->bus_clk);
>> +	reset_control_assert(mixer->reset);
>> +}
>> +
>> +static const struct component_ops sun8i_mixer_ops = {
>> +	.bind	= sun8i_mixer_bind,
>> +	.unbind	= sun8i_mixer_unbind,
>> +};
>> +
>> +static int sun8i_mixer_probe(struct platform_device *pdev)
>> +{
>> +	return component_add(&pdev->dev, &sun8i_mixer_ops);
>> +}
>> +
>> +static int sun8i_mixer_remove(struct platform_device *pdev)
>> +{
>> +	component_del(&pdev->dev, &sun8i_mixer_ops);
>> +
>> +	return 0;
>> +}
>> +
>> +static const struct sun8i_mixer_cfg sun8i_v3s_mixer_cfg = {
>> +	.vi_num = 2,
>> +	.ui_num = 1,
>> +};
>> +
>> +static const struct of_device_id sun8i_mixer_of_table[] = {
>> +	{
>> +		.compatible = "allwinner,sun8i-v3s-de2-mixer",
>> +		.data = &sun8i_v3s_mixer_cfg,
>> +	},
>> +	{ }
>> +};
>> +MODULE_DEVICE_TABLE(of, sun8i_mixer_of_table);
>> +
>> +static struct platform_driver sun8i_mixer_platform_driver = {
>> +	.probe		= sun8i_mixer_probe,
>> +	.remove		= sun8i_mixer_remove,
>> +	.driver		= {
>> +		.name		= "sun8i-mixer",
>> +		.of_match_table	= sun8i_mixer_of_table,
>> +	},
>> +};
>> +module_platform_driver(sun8i_mixer_platform_driver);
>> +
>> +MODULE_AUTHOR("Icenowy Zheng <icenowy@aosc.io>");
>> +MODULE_DESCRIPTION("Allwinner DE2 Mixer driver");
>> +MODULE_LICENSE("GPL");
>> diff --git a/drivers/gpu/drm/sun4i/sun8i_mixer.h
>b/drivers/gpu/drm/sun4i/sun8i_mixer.h
>> new file mode 100644
>> index 000000000000..a4a365ae44c9
>> --- /dev/null
>> +++ b/drivers/gpu/drm/sun4i/sun8i_mixer.h
>> @@ -0,0 +1,131 @@
>> +/*
>> + * Copyright (C) 2017 Icenowy Zheng <icenowy@aosc.io>
>> + *
>> + * This program is free software; you can redistribute it and/or
>> + * modify it under the terms of the GNU General Public License as
>> + * published by the Free Software Foundation; either version 2 of
>> + * the License, or (at your option) any later version.
>> + */
>> +
>> +#ifndef _SUN8I_MIXER_H_
>> +#define _SUN8I_MIXER_H_
>> +
>> +#include <linux/clk.h>
>> +#include <linux/regmap.h>
>> +#include <linux/reset.h>
>> +
>> +#include "sun4i_layer.h"
>> +
>> +#define SUN8I_MIXER_MAX_CHAN_COUNT		4
>> +
>> +#define SUN8I_MIXER_SIZE(w, h)			(((h) - 1) << 16 | ((w) - 1))
>> +#define SUN8I_MIXER_COORD(x, y)			((y) << 16 | (x))
>> +
>> +#define SUN8I_MIXER_GLOBAL_CTL			0x0
>> +#define SUN8I_MIXER_GLOBAL_STATUS		0x4
>> +#define SUN8I_MIXER_GLOBAL_DBUFF		0x8
>> +#define SUN8I_MIXER_GLOBAL_SIZE			0xc
>> +
>> +#define SUN8I_MIXER_GLOBAL_CTL_RT_EN		0x1
>> +
>> +#define SUN8I_MIXER_GLOBAL_DBUFF_ENABLE		0x1
>> +
>> +#define SUN8I_MIXER_BLEND_FCOLOR_CTL		0x1000
>> +#define SUN8I_MIXER_BLEND_ATTR_FCOLOR(x)	(0x1004 + 0x10 * (x) + 0x0)
>> +#define SUN8I_MIXER_BLEND_ATTR_INSIZE(x)	(0x1004 + 0x10 * (x) + 0x4)
>> +#define SUN8I_MIXER_BLEND_ATTR_OFFSET(x)	(0x1004 + 0x10 * (x) + 0x8)
>> +#define SUN8I_MIXER_BLEND_ROUTE			0x1080
>> +#define SUN8I_MIXER_BLEND_PREMULTIPLY		0x1084
>> +#define SUN8I_MIXER_BLEND_BKCOLOR		0x1088
>> +#define SUN8I_MIXER_BLEND_OUTSIZE		0x108c
>> +#define SUN8I_MIXER_BLEND_MODE(x)		(0x1090 + 0x04 * (x))
>> +#define SUN8I_MIXER_BLEND_CK_CTL		0x10b0
>> +#define SUN8I_MIXER_BLEND_CK_CFG		0x10b4
>> +#define SUN8I_MIXER_BLEND_CK_MAX(x)		(0x10c0 + 0x04 * (x))
>> +#define SUN8I_MIXER_BLEND_CK_MIN(x)		(0x10e0 + 0x04 * (x))
>> +#define SUN8I_MIXER_BLEND_OUTCTL		0x10fc
>> +
>> +/* The following numbers are some still unknown magic numbers */
>> +#define SUN8I_MIXER_BLEND_ATTR_FCOLOR_DEF	0xff000000
>> +#define SUN8I_MIXER_BLEND_FCOLOR_CTL_DEF	0x00000101
>> +#define SUN8I_MIXER_BLEND_PREMULTIPLY_DEF	0x0
>> +#define SUN8I_MIXER_BLEND_BKCOLOR_DEF		0xff000000
>> +#define SUN8I_MIXER_BLEND_MODE_DEF		0x03010301
>> +#define SUN8I_MIXER_BLEND_CK_CTL_DEF		0x0
>> +
>> +#define SUN8I_MIXER_BLEND_OUTCTL_INTERLACED	BIT(1)
>> +
>> +/*
>> + * VI channels are not used now, but the support of them may be
>introduced in
>> + * the future.
>> + */
>> +
>> +#define SUN8I_MIXER_CHAN_UI_LAYER_ATTR(ch, layer) \
>> +			(0x2000 + 0x1000 * (ch) + 0x20 * (layer) + 0x0)
>> +#define SUN8I_MIXER_CHAN_UI_LAYER_SIZE(ch, layer) \
>> +			(0x2000 + 0x1000 * (ch) + 0x20 * (layer) + 0x4)
>> +#define SUN8I_MIXER_CHAN_UI_LAYER_COORD(ch, layer) \
>> +			(0x2000 + 0x1000 * (ch) + 0x20 * (layer) + 0x8)
>> +#define SUN8I_MIXER_CHAN_UI_LAYER_PITCH(ch, layer) \
>> +			(0x2000 + 0x1000 * (ch) + 0x20 * (layer) + 0xc)
>> +#define SUN8I_MIXER_CHAN_UI_LAYER_TOP_LADDR(ch, layer) \
>> +			(0x2000 + 0x1000 * (ch) + 0x20 * (layer) + 0x10)
>> +#define SUN8I_MIXER_CHAN_UI_LAYER_BOT_LADDR(ch, layer) \
>> +			(0x2000 + 0x1000 * (ch) + 0x20 * (layer) + 0x14)
>> +#define SUN8I_MIXER_CHAN_UI_LAYER_FCOLOR(ch, layer) \
>> +			(0x2000 + 0x1000 * (ch) + 0x20 * (layer) + 0x18)
>> +#define SUN8I_MIXER_CHAN_UI_TOP_HADDR(ch)	(0x2000 + 0x1000 * (ch) +
>0x80)
>> +#define SUN8I_MIXER_CHAN_UI_BOT_HADDR(ch)	(0x2000 + 0x1000 * (ch) +
>0x84)
>> +#define SUN8I_MIXER_CHAN_UI_OVL_SIZE(ch)	(0x2000 + 0x1000 * (ch) +
>0x88)
>> +
>> +#define SUN8I_MIXER_CHAN_UI_LAYER_ATTR_EN		BIT(0)
>> +#define SUN8I_MIXER_CHAN_UI_LAYER_ATTR_ALPHA_MODE_MASK	GENMASK(2, 1)
>> +#define SUN8I_MIXER_CHAN_UI_LAYER_ATTR_FBFMT_MASK	GENMASK(11, 8)
>> +#define SUN8I_MIXER_CHAN_UI_LAYER_ATTR_ALPHA_MASK	GENMASK(31, 24)
>> +#define SUN8I_MIXER_CHAN_UI_LAYER_ATTR_ALPHA_MODE_DEF	(1 << 1)
>> +#define SUN8I_MIXER_CHAN_UI_LAYER_ATTR_FBFMT_ARGB8888	(0 << 8)
>> +#define SUN8I_MIXER_CHAN_UI_LAYER_ATTR_FBFMT_XRGB8888	(4 << 8)
>> +#define SUN8I_MIXER_CHAN_UI_LAYER_ATTR_FBFMT_RGB888	(8 << 8)
>> +#define SUN8I_MIXER_CHAN_UI_LAYER_ATTR_ALPHA_DEF	(0xff << 24)
>> +
>> +/*
>> + * These sub-engines are still unknown now, the EN registers are
>here only to
>> + * be used to disable these sub-engines.
>> + */
>> +#define SUN8I_MIXER_VSU_EN			0x20000
>> +#define SUN8I_MIXER_GSU1_EN			0x30000
>> +#define SUN8I_MIXER_GSU2_EN			0x40000
>> +#define SUN8I_MIXER_GSU3_EN			0x50000
>> +#define SUN8I_MIXER_FCE_EN			0xa0000
>> +#define SUN8I_MIXER_BWS_EN			0xa2000
>> +#define SUN8I_MIXER_LTI_EN			0xa4000
>> +#define SUN8I_MIXER_PEAK_EN			0xa6000
>> +#define SUN8I_MIXER_ASE_EN			0xa8000
>> +#define SUN8I_MIXER_FCC_EN			0xaa000
>> +#define SUN8I_MIXER_DCSC_EN			0xb0000
>> +
>> +struct sun8i_mixer_cfg {
>> +	int		vi_num;
>> +	int		ui_num;
>> +};
>> +
>> +struct sun8i_mixer {
>> +	struct regmap			*regs;
>> +
>> +	const struct sun8i_mixer_cfg	*cfg;
>> +
>> +	struct reset_control		*reset;
>> +
>> +	struct clk			*bus_clk;
>> +	struct clk			*mod_clk;
>> +};
>> +
>> +void sun8i_mixer_layer_enable(struct sun8i_mixer *mixer,
>> +				int layer, bool enable);
>> +int sun8i_mixer_update_layer_coord(struct sun8i_mixer *mixer,
>> +				     int layer, struct drm_plane *plane);
>> +int sun8i_mixer_update_layer_formats(struct sun8i_mixer *mixer,
>> +				       int layer, struct drm_plane *plane);
>> +int sun8i_mixer_update_layer_buffer(struct sun8i_mixer *mixer,
>> +				      int layer, struct drm_plane *plane);
>> +#endif /* _SUN8I_MIXER_H_ */
>
>Thanks,
>Maxime

  reply	other threads:[~2017-04-18 10:49 UTC|newest]

Thread overview: 75+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2017-04-16 12:08 [PATCH v4 00/11] Initial Allwinner Display Engine 2.0 Support Icenowy Zheng
2017-04-16 12:08 ` Icenowy Zheng
2017-04-16 12:08 ` Icenowy Zheng
2017-04-16 12:08 ` [PATCH v4 01/11] dt-bindings: add binding for the Allwinner DE2 CCU Icenowy Zheng
2017-04-16 12:08   ` Icenowy Zheng
2017-04-16 12:08   ` Icenowy Zheng
2017-04-20 13:58   ` Rob Herring
2017-04-20 13:58     ` Rob Herring
2017-04-20 13:58     ` Rob Herring
2017-04-16 12:08 ` [PATCH v4 02/11] clk: sunxi-ng: add support for " Icenowy Zheng
2017-04-16 12:08   ` Icenowy Zheng
2017-04-16 12:08   ` Icenowy Zheng
2017-04-20 14:02   ` Rob Herring
2017-04-20 14:02     ` Rob Herring
2017-04-20 14:36     ` Maxime Ripard
2017-04-20 14:36       ` Maxime Ripard
2017-04-20 14:36       ` Maxime Ripard
2017-04-20 22:36       ` Rob Herring
2017-04-20 22:36         ` Rob Herring
2017-04-20 22:36         ` Rob Herring
2017-04-20 22:36         ` Rob Herring
2017-04-16 12:08 ` [PATCH v4 03/11] dt-bindings: add bindings for DE2 on V3s SoC Icenowy Zheng
2017-04-16 12:08   ` Icenowy Zheng
2017-04-16 12:08   ` Icenowy Zheng
2017-04-20 14:05   ` Rob Herring
2017-04-20 14:05     ` Rob Herring
2017-04-20 14:05     ` Rob Herring
2017-04-16 12:08 ` [PATCH v4 04/11] drm/sun4i: return only planes for layers created Icenowy Zheng
2017-04-16 12:08   ` Icenowy Zheng
2017-04-16 12:08   ` Icenowy Zheng
2017-04-16 12:08 ` [PATCH v4 05/11] drm/sun4i: abstract a engine type Icenowy Zheng
2017-04-16 12:08   ` Icenowy Zheng
2017-04-16 12:08   ` Icenowy Zheng
2017-04-18  8:55   ` Maxime Ripard
2017-04-18  8:55     ` Maxime Ripard
2017-04-18  8:55     ` Maxime Ripard
2017-04-18  8:55     ` Maxime Ripard
2017-04-18 11:05     ` Icenowy Zheng
2017-04-18 11:05       ` Icenowy Zheng
2017-04-18 11:05       ` Icenowy Zheng
2017-04-18 11:05       ` Icenowy Zheng
2017-04-20 14:39       ` Maxime Ripard
2017-04-20 14:39         ` Maxime Ripard
2017-04-20 14:39         ` Maxime Ripard
2017-04-16 12:08 ` [PATCH v4 06/11] drm/sun4i: add support for Allwinner DE2 mixers Icenowy Zheng
2017-04-16 12:08   ` Icenowy Zheng
2017-04-16 12:08   ` Icenowy Zheng
2017-04-18  9:00   ` Maxime Ripard
2017-04-18  9:00     ` Maxime Ripard
2017-04-18  9:00     ` Maxime Ripard
2017-04-18  9:00     ` Maxime Ripard
2017-04-18 10:47     ` Icenowy Zheng [this message]
2017-04-18 10:47       ` Icenowy Zheng
2017-04-18 10:47       ` Icenowy Zheng
2017-04-20  8:37       ` Maxime Ripard
2017-04-20  8:37         ` Maxime Ripard
2017-04-20  8:37         ` Maxime Ripard
2017-04-21  8:18         ` icenowy
2017-04-21  8:18           ` icenowy at aosc.io
2017-04-21  8:18           ` icenowy-h8G6r0blFSE
2017-04-16 12:08 ` [PATCH v4 07/11] drm/sun4i: Add compatible string for V3s display engine Icenowy Zheng
2017-04-16 12:08   ` Icenowy Zheng
2017-04-16 12:08   ` Icenowy Zheng
2017-04-16 12:08 ` [PATCH v4 08/11] drm/sun4i: tcon: add support for V3s TCON Icenowy Zheng
2017-04-16 12:08   ` Icenowy Zheng
2017-04-16 12:08   ` Icenowy Zheng
2017-04-16 12:08 ` [PATCH v4 09/11] ARM: dts: sun8i: add DE2 nodes for V3s SoC Icenowy Zheng
2017-04-16 12:08   ` Icenowy Zheng
2017-04-16 12:08   ` Icenowy Zheng
2017-04-16 12:08 ` [PATCH v4 10/11] ARM: dts: sun8i: add pinmux for LCD pins of " Icenowy Zheng
2017-04-16 12:08   ` Icenowy Zheng
2017-04-16 12:08   ` Icenowy Zheng
2017-04-16 12:08 ` [PATCH v4 11/11] [DO NOT MERGE] ARM: dts: sun8i: enable LCD panel of Lichee Pi Zero Icenowy Zheng
2017-04-16 12:08   ` Icenowy Zheng
2017-04-16 12:08   ` Icenowy Zheng

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=88F5FAC9-1873-4C76-9AB9-FF361C07664E@aosc.io \
    --to=icenowy@aosc.io \
    --cc=airlied@linux.ie \
    --cc=devicetree@vger.kernel.org \
    --cc=dri-devel@lists.freedesktop.org \
    --cc=jernej.skrabec@siol.net \
    --cc=linux-arm-kernel@lists.infradead.org \
    --cc=linux-clk@vger.kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-sunxi@googlegroups.com \
    --cc=maxime.ripard@free-electrons.com \
    --cc=robh+dt@kernel.org \
    --cc=wens@csie.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.