diff mbox

[v3,1/4] drm/layerscape: Add Freescale DCU DRM driver

Message ID 1427348225-40731-1-git-send-email-b52261@freescale.com
State Superseded, archived
Headers show

Commit Message

Jianwei Wang March 26, 2015, 5:37 a.m. UTC
This patch add support for Two Dimensional Animation and Compositing
Engine (2D-ACE) on the Freescale SoCs.

2D-ACE is a Freescale display controller. 2D-ACE describes
the functionality of the module extremely well its name is a value
that cannot be used as a token in programming languages.
Instead the valid token "DCU" is used to tag the register names and
function names.

The Display Controller Unit (DCU) module is a system master that
fetches graphics stored in internal or external memory and displays
them on a TFT LCD panel. A wide range of panel sizes is supported
and the timing of the interface signals is highly configurable.
Graphics are read directly from memory and then blended in real-time,
which allows for dynamic content creation with minimal CPU
intervention.

The features:
(1) Full RGB888 output to TFT LCD panel.
(2) For the current LCD panel, WQVGA "480x272" is supported.
(3) Blending of each pixel using up to 4 source layers
dependent on size of panel.
(4) Each graphic layer can be placed with one pixel resolution
in either axis.
(5) Each graphic layer support RGB565 and RGB888 direct colors
without alpha channel
and BGRA8888 direct colors with an alpha channel.
(6) Each graphic layer support alpha blending with 8-bit
resolution.

This is a simplified version, only one primary plane, one
framebuffer created for fbdev, one crtc, one connector for
TFT LCD panel, an encoder.

Signed-off-by: Alison Wang <b18965@freescale.com>
Signed-off-by: Xiubo Li <lixiubo@cmss.chinamobile.com>
Signed-off-by: Jianwei Wang <b52261@freescale.com>
---

Changed in V3:

- Test driver on Vybrid board and add compatible string
- Remove unused functions
- set default crtc for encoder
- replace legacy functions with atomic help functions
- Set the unique name of the DRM device
- Implement irq handle function for vblank interrupt

Changed in v2: 
- Add atomic support
- Modify bindings file
- Rename node for compatibility
- Move platform related code out for compatibility

 .../devicetree/bindings/drm/fsl/fsl,dcu.txt        |  50 ++++
 drivers/gpu/drm/Kconfig                            |   2 +
 drivers/gpu/drm/Makefile                           |   1 +
 drivers/gpu/drm/fsl/Kconfig                        |  17 ++
 drivers/gpu/drm/fsl/Makefile                       |   8 +
 drivers/gpu/drm/fsl/fsl_dcu_drm_connector.c        | 193 ++++++++++++
 drivers/gpu/drm/fsl/fsl_dcu_drm_connector.h        |  30 ++
 drivers/gpu/drm/fsl/fsl_dcu_drm_crtc.c             | 165 ++++++++++
 drivers/gpu/drm/fsl/fsl_dcu_drm_crtc.h             |  26 ++
 drivers/gpu/drm/fsl/fsl_dcu_drm_drv.c              | 331 +++++++++++++++++++++
 drivers/gpu/drm/fsl/fsl_dcu_drm_drv.h              | 210 +++++++++++++
 drivers/gpu/drm/fsl/fsl_dcu_drm_fbdev.c            |  26 ++
 drivers/gpu/drm/fsl/fsl_dcu_drm_kms.c              |  42 +++
 drivers/gpu/drm/fsl/fsl_dcu_drm_kms.h              |  17 ++
 drivers/gpu/drm/fsl/fsl_dcu_drm_plane.c            | 192 ++++++++++++
 drivers/gpu/drm/fsl/fsl_dcu_drm_plane.h            |  23 ++
 16 files changed, 1333 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/drm/fsl/fsl,dcu.txt
 create mode 100644 drivers/gpu/drm/fsl/Kconfig
 create mode 100644 drivers/gpu/drm/fsl/Makefile
 create mode 100644 drivers/gpu/drm/fsl/fsl_dcu_drm_connector.c
 create mode 100644 drivers/gpu/drm/fsl/fsl_dcu_drm_connector.h
 create mode 100644 drivers/gpu/drm/fsl/fsl_dcu_drm_crtc.c
 create mode 100644 drivers/gpu/drm/fsl/fsl_dcu_drm_crtc.h
 create mode 100644 drivers/gpu/drm/fsl/fsl_dcu_drm_drv.c
 create mode 100644 drivers/gpu/drm/fsl/fsl_dcu_drm_drv.h
 create mode 100644 drivers/gpu/drm/fsl/fsl_dcu_drm_fbdev.c
 create mode 100644 drivers/gpu/drm/fsl/fsl_dcu_drm_kms.c
 create mode 100644 drivers/gpu/drm/fsl/fsl_dcu_drm_kms.h
 create mode 100644 drivers/gpu/drm/fsl/fsl_dcu_drm_plane.c
 create mode 100644 drivers/gpu/drm/fsl/fsl_dcu_drm_plane.h

Comments

Stefan Agner March 31, 2015, 8:49 a.m. UTC | #1
Hi Jianwei,

The driver worked on a Vybrid VF610 device using the exported
framebuffer. However, when using X-Server through the DRM interface
directly (by using the modesetting driver) I get just a black screen so
far, still investigating the reason. What user-space interfaces did you
test?

When using the FB device and insert a USB HID device, I get some
flickers on the screen. I didn't had those on the dcufb driver, did you
notice something like this too? Probably related to the resolution, I'm
using VGA resolution.

Some comments below.


On 2015-03-26 06:37, Jianwei Wang wrote:
> This patch add support for Two Dimensional Animation and Compositing
> Engine (2D-ACE) on the Freescale SoCs.
> 
> 2D-ACE is a Freescale display controller. 2D-ACE describes
> the functionality of the module extremely well its name is a value
> that cannot be used as a token in programming languages.
> Instead the valid token "DCU" is used to tag the register names and
> function names.
> 
> The Display Controller Unit (DCU) module is a system master that
> fetches graphics stored in internal or external memory and displays
> them on a TFT LCD panel. A wide range of panel sizes is supported
> and the timing of the interface signals is highly configurable.
> Graphics are read directly from memory and then blended in real-time,
> which allows for dynamic content creation with minimal CPU
> intervention.
> 
> The features:
> (1) Full RGB888 output to TFT LCD panel.
> (2) For the current LCD panel, WQVGA "480x272" is supported.
> (3) Blending of each pixel using up to 4 source layers
> dependent on size of panel.

modetest only shows one layer currently...

> (4) Each graphic layer can be placed with one pixel resolution
> in either axis.
> (5) Each graphic layer support RGB565 and RGB888 direct colors
> without alpha channel
> and BGRA8888 direct colors with an alpha channel.

The array fsl_dcu_drm_plane_formats below shows more formats, does this
commit log needs updating?

> (6) Each graphic layer support alpha blending with 8-bit
> resolution.
> 
> This is a simplified version, only one primary plane, one
> framebuffer created for fbdev, one crtc, one connector for
> TFT LCD panel, an encoder.
> 
> Signed-off-by: Alison Wang <b18965@freescale.com>
> Signed-off-by: Xiubo Li <lixiubo@cmss.chinamobile.com>
> Signed-off-by: Jianwei Wang <b52261@freescale.com>
> ---
> 
> Changed in V3:
> 
> - Test driver on Vybrid board and add compatible string
> - Remove unused functions
> - set default crtc for encoder
> - replace legacy functions with atomic help functions
> - Set the unique name of the DRM device
> - Implement irq handle function for vblank interrupt
> 
> Changed in v2: 
> - Add atomic support
> - Modify bindings file
> - Rename node for compatibility
> - Move platform related code out for compatibility
> 
>  .../devicetree/bindings/drm/fsl/fsl,dcu.txt        |  50 ++++
>  drivers/gpu/drm/Kconfig                            |   2 +
>  drivers/gpu/drm/Makefile                           |   1 +
>  drivers/gpu/drm/fsl/Kconfig                        |  17 ++
>  drivers/gpu/drm/fsl/Makefile                       |   8 +
>  drivers/gpu/drm/fsl/fsl_dcu_drm_connector.c        | 193 ++++++++++++
>  drivers/gpu/drm/fsl/fsl_dcu_drm_connector.h        |  30 ++
>  drivers/gpu/drm/fsl/fsl_dcu_drm_crtc.c             | 165 ++++++++++
>  drivers/gpu/drm/fsl/fsl_dcu_drm_crtc.h             |  26 ++
>  drivers/gpu/drm/fsl/fsl_dcu_drm_drv.c              | 331 +++++++++++++++++++++
>  drivers/gpu/drm/fsl/fsl_dcu_drm_drv.h              | 210 +++++++++++++
>  drivers/gpu/drm/fsl/fsl_dcu_drm_fbdev.c            |  26 ++
>  drivers/gpu/drm/fsl/fsl_dcu_drm_kms.c              |  42 +++
>  drivers/gpu/drm/fsl/fsl_dcu_drm_kms.h              |  17 ++
>  drivers/gpu/drm/fsl/fsl_dcu_drm_plane.c            | 192 ++++++++++++
>  drivers/gpu/drm/fsl/fsl_dcu_drm_plane.h            |  23 ++
>  16 files changed, 1333 insertions(+)
>  create mode 100644 Documentation/devicetree/bindings/drm/fsl/fsl,dcu.txt
>  create mode 100644 drivers/gpu/drm/fsl/Kconfig
>  create mode 100644 drivers/gpu/drm/fsl/Makefile
>  create mode 100644 drivers/gpu/drm/fsl/fsl_dcu_drm_connector.c
>  create mode 100644 drivers/gpu/drm/fsl/fsl_dcu_drm_connector.h
>  create mode 100644 drivers/gpu/drm/fsl/fsl_dcu_drm_crtc.c
>  create mode 100644 drivers/gpu/drm/fsl/fsl_dcu_drm_crtc.h
>  create mode 100644 drivers/gpu/drm/fsl/fsl_dcu_drm_drv.c
>  create mode 100644 drivers/gpu/drm/fsl/fsl_dcu_drm_drv.h
>  create mode 100644 drivers/gpu/drm/fsl/fsl_dcu_drm_fbdev.c
>  create mode 100644 drivers/gpu/drm/fsl/fsl_dcu_drm_kms.c
>  create mode 100644 drivers/gpu/drm/fsl/fsl_dcu_drm_kms.h
>  create mode 100644 drivers/gpu/drm/fsl/fsl_dcu_drm_plane.c
>  create mode 100644 drivers/gpu/drm/fsl/fsl_dcu_drm_plane.h
> 
> diff --git a/Documentation/devicetree/bindings/drm/fsl/fsl,dcu.txt
> b/Documentation/devicetree/bindings/drm/fsl/fsl,dcu.txt
> new file mode 100644
> index 0000000..bdc7d5b
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/drm/fsl/fsl,dcu.txt
> @@ -0,0 +1,50 @@
> +Device Tree bindings for Freescale DCU DRM Driver
> +
> +Required properties:
> +- compatible:           Should be one of
> +	* "fsl,ls1021a-dcu".
> +	* "fsl,vf610-dcu".

In the Vybrid reference manual, that IP is denoted as "DCU4". Any reason
why you left out the DCU version? Is this different for LS1021a? On the
other hand, with the SoC in the name, the IP should be specified clear
enough.

> +- reg:                  Address and length of the register set for dcu.
> +- clocks:               From common clock binding: handle to dcu clock.
> +- clock-names:          From common clock binding: Shall be "dcu".
> +- display:              The phandle to display node.
> +
> +Required properties:
> +- bits-per-pixel:       <16> for RGB565,
> +			<24> for RGB888,
> +			<32> for RGB8888.
> +
> +Required timing node for dispplay sub-node:
> +- display-timings:      Refer to binding doc display-timing.txt for details.
> +
> +Examples:
> +dcu: dcu@2ce0000 {
> +	compatible = "fsl,ls1021a-dcu";
> +	reg = <0x0 0x2ce0000 0x0 0x10000>;
> +	clocks = <&platform_clk 0>;
> +	clock-names = "dcu";
> +	big-endian;
> +	display = <&display>;
> +
> +	display: display@0 {
> +		bits-per-pixel = <24>;
> +
> +		display-timings {
> +			native-mode = <&timing0>;
> +			timing0: nl4827hc19 {
> +				clock-frequency = <10870000>;
> +				hactive = <480>;
> +				vactive = <272>;
> +				hback-porch = <2>;
> +				hfront-porch = <2>;
> +				vback-porch = <1>;
> +				vfront-porch = <1>;
> +				hsync-len = <41>;
> +				vsync-len = <2>;
> +				hsync-active = <1>;
> +				vsync-active = <1>;
> +			};
> +		};
> +	};
> +};
> +
> diff --git a/drivers/gpu/drm/Kconfig b/drivers/gpu/drm/Kconfig
> index 151a050..a6957aa 100644
> --- a/drivers/gpu/drm/Kconfig
> +++ b/drivers/gpu/drm/Kconfig
> @@ -199,6 +199,8 @@ source "drivers/gpu/drm/bochs/Kconfig"
>  
>  source "drivers/gpu/drm/msm/Kconfig"
>  
> +source "drivers/gpu/drm/fsl/Kconfig"
> +
>  source "drivers/gpu/drm/tegra/Kconfig"
>  
>  source "drivers/gpu/drm/panel/Kconfig"
> diff --git a/drivers/gpu/drm/Makefile b/drivers/gpu/drm/Makefile
> index 2c239b9..ab5b9ef 100644
> --- a/drivers/gpu/drm/Makefile
> +++ b/drivers/gpu/drm/Makefile
> @@ -56,6 +56,7 @@ obj-$(CONFIG_DRM_UDL) += udl/
>  obj-$(CONFIG_DRM_AST) += ast/
>  obj-$(CONFIG_DRM_ARMADA) += armada/
>  obj-$(CONFIG_DRM_ATMEL_HLCDC)	+= atmel-hlcdc/
> +obj-$(CONFIG_DRM_FSL_DCU) += fsl/

Hm, I'm wondering whether it would be a good idea to store that driver
under fsl-dcu/... Any opinion?

>  obj-$(CONFIG_DRM_RCAR_DU) += rcar-du/
>  obj-$(CONFIG_DRM_SHMOBILE) +=shmobile/
>  obj-$(CONFIG_DRM_OMAP)	+= omapdrm/
> diff --git a/drivers/gpu/drm/fsl/Kconfig b/drivers/gpu/drm/fsl/Kconfig
> new file mode 100644
> index 0000000..e4f8df0
> --- /dev/null
> +++ b/drivers/gpu/drm/fsl/Kconfig
> @@ -0,0 +1,17 @@
> +config DRM_FSL_DCU
> +	tristate "DRM Support for Freescale DCU"
> +	depends on DRM && OF && ARM
> +	select DRM_KMS_HELPER
> +	select DRM_KMS_CMA_HELPER
> +	select VIDEOMODE_HELPERS
> +	select BACKLIGHT_CLASS_DEVICE
> +	select BACKLIGHT_LCD_SUPPORT
> +	select REGMAP_MMIO
> +	select DRM_KMS_FB_HELPER
> +	select FB_SYS_FILLRECT
> +	select FB_SYS_COPYAREA
> +	select FB_SYS_IMAGEBLIT
> +	select FB_SYS_FOPS
> +	help
> +	  Choose this option if you have an Freescale DCU chipset.
> +	  If M is selected the module will be called fsl-dcu-drm.
> diff --git a/drivers/gpu/drm/fsl/Makefile b/drivers/gpu/drm/fsl/Makefile
> new file mode 100644
> index 0000000..5f74aee
> --- /dev/null
> +++ b/drivers/gpu/drm/fsl/Makefile
> @@ -0,0 +1,8 @@
> +fsl-dcu-drm-y := fsl_dcu_drm_drv.o \
> +	       fsl_dcu_drm_kms.o \
> +	       fsl_dcu_drm_connector.o \
> +	       fsl_dcu_drm_plane.o \
> +	       fsl_dcu_drm_crtc.o \
> +	       fsl_dcu_drm_fbdev.o \
> +
> +obj-$(CONFIG_DRM_FSL_DCU)	+= fsl-dcu-drm.o
> diff --git a/drivers/gpu/drm/fsl/fsl_dcu_drm_connector.c
> b/drivers/gpu/drm/fsl/fsl_dcu_drm_connector.c
> new file mode 100644
> index 0000000..4610647
> --- /dev/null
> +++ b/drivers/gpu/drm/fsl/fsl_dcu_drm_connector.c
> @@ -0,0 +1,193 @@
> +/*
> + * Copyright 2015 Freescale Semiconductor, Inc.
> + *
> + * Freescale DCU drm device driver
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License as published by
> + * the Free Software Foundation; either version 2 of the License, or
> + * (at your option) any later version.
> + */
> +
> +#include <linux/backlight.h>
> +
> +#include <drm/drmP.h>
> +#include <drm/drm_atomic_helper.h>
> +#include <video/of_display_timing.h>
> +
> +#include "fsl_dcu_drm_drv.h"
> +#include "fsl_dcu_drm_connector.h"
> +
> +static void fsl_dcu_drm_encoder_dpms(struct drm_encoder *encoder, int mode)
> +{
> +}
> +
> +static void fsl_dcu_drm_encoder_mode_prepare(struct drm_encoder *encoder)
> +{
> +}
> +
> +static void fsl_dcu_drm_encoder_mode_set(struct drm_encoder *encoder,
> +					 struct drm_display_mode *mode,
> +					 struct drm_display_mode *adjusted_mode)
> +{
> +}
> +
> +static void fsl_dcu_drm_encoder_mode_commit(struct drm_encoder *encoder)
> +{
> +}
> +
> +static void fsl_dcu_drm_encoder_disable(struct drm_encoder *encoder)
> +{
> +}
> +
> +static int
> +fsl_dcu_drm_encoder_atomic_check(struct drm_encoder *encoder,
> +				 struct drm_crtc_state *crtc_state,
> +				 struct drm_connector_state *conn_state)
> +{
> +	return 0;
> +}
> +
> +static void fsl_dcu_drm_encoder_destroy(struct drm_encoder *encoder)
> +{
> +	drm_encoder_cleanup(encoder);
> +}
> +
> +static const struct drm_encoder_helper_funcs encoder_helper_funcs = {
> +	.dpms = fsl_dcu_drm_encoder_dpms,
> +	.prepare = fsl_dcu_drm_encoder_mode_prepare,
> +	.commit = fsl_dcu_drm_encoder_mode_commit,
> +	.mode_set = fsl_dcu_drm_encoder_mode_set,
> +	.disable = fsl_dcu_drm_encoder_disable,
> +	.atomic_check = fsl_dcu_drm_encoder_atomic_check,
> +};
> +
> +static const struct drm_encoder_funcs encoder_funcs = {
> +	.destroy = fsl_dcu_drm_encoder_destroy,
> +};
> +
> +int fsl_dcu_drm_encoder_create(struct fsl_dcu_drm_device *fsl_dev,
> +			       struct fsl_dcu_drm_crtc *crtc)
> +{
> +	struct drm_encoder *encoder = &fsl_dev->encoder;
> +	int ret;
> +
> +	ret = drm_encoder_init(fsl_dev->ddev, encoder, &encoder_funcs,
> +			       DRM_MODE_ENCODER_LVDS);
> +	if (ret < 0)
> +		return ret;
> +
> +	drm_encoder_helper_add(encoder, &encoder_helper_funcs);
> +	encoder->crtc = &crtc->crtc;
> +
> +	return 0;
> +}
> +
> +#define to_fsl_dcu_connector(connector) \
> +	container_of(connector, struct fsl_dcu_drm_connector, connector)
> +
> +static int fsl_dcu_drm_connector_get_modes(struct drm_connector *connector)
> +{
> +	struct drm_device *dev = connector->dev;
> +	struct device_node *display_np, *np = dev->dev->of_node;
> +	struct drm_display_mode *mode = drm_mode_create(connector->dev);
> +	int num_modes = 0;
> +
> +	if (np) {
> +		display_np = of_parse_phandle(np, "display", 0);
> +		if (!display_np) {
> +			dev_err(dev->dev, "failed to find display phandle\n");
> +			return num_modes;
> +		}
> +		of_get_drm_display_mode(display_np, mode, OF_USE_NATIVE_MODE);
> +		mode->type |= DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED,
> +		drm_mode_probed_add(connector, mode);
> +		num_modes++;
> +	}
> +
> +	return num_modes;
> +}
> +
> +static int fsl_dcu_drm_connector_mode_valid(struct drm_connector *connector,
> +					    struct drm_display_mode *mode)
> +{
> +	return MODE_OK;
> +}
> +
> +static struct drm_encoder *
> +fsl_dcu_drm_connector_best_encoder(struct drm_connector *connector)
> +{
> +	struct fsl_dcu_drm_connector *fsl_con = to_fsl_dcu_connector(connector);
> +
> +	return fsl_con->encoder;
> +}
> +
> +static void fsl_dcu_drm_connector_destroy(struct drm_connector *connector)
> +{
> +	drm_connector_unregister(connector);
> +	drm_connector_cleanup(connector);
> +}
> +
> +static enum drm_connector_status
> +fsl_dcu_drm_connector_detect(struct drm_connector *connector, bool force)
> +{
> +	return connector_status_connected;
> +}
> +
> +static const struct drm_connector_funcs fsl_dcu_drm_connector_funcs = {
> +	.dpms = drm_atomic_helper_connector_dpms,
> +	.reset = drm_atomic_helper_connector_reset,
> +	.detect = fsl_dcu_drm_connector_detect,
> +	.fill_modes = drm_helper_probe_single_connector_modes,
> +	.destroy = fsl_dcu_drm_connector_destroy,
> +	.atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
> +	.atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
> +};
> +
> +static const struct drm_connector_helper_funcs connector_helper_funcs = {
> +	.get_modes = fsl_dcu_drm_connector_get_modes,
> +	.mode_valid = fsl_dcu_drm_connector_mode_valid,
> +	.best_encoder = fsl_dcu_drm_connector_best_encoder,
> +};
> +
> +int fsl_dcu_drm_connector_create(struct fsl_dcu_drm_device *fsl_dev,
> +				 struct drm_encoder *encoder)
> +{
> +	struct drm_connector *connector = &fsl_dev->connector.connector;
> +	int ret;
> +
> +	fsl_dev->connector.encoder = encoder;
> +
> +	connector->display_info.width_mm = 0;
> +	connector->display_info.height_mm = 0;
> +
> +	ret = drm_connector_init(fsl_dev->ddev, connector,
> +				 &fsl_dcu_drm_connector_funcs,
> +				 DRM_MODE_CONNECTOR_LVDS);
> +	if (ret < 0)
> +		return ret;
> +
> +	connector->dpms = DRM_MODE_DPMS_OFF;
> +	drm_connector_helper_add(connector, &connector_helper_funcs);
> +	ret = drm_connector_register(connector);
> +	if (ret < 0)
> +		goto err_cleanup;
> +
> +	ret = drm_mode_connector_attach_encoder(connector, encoder);
> +	if (ret < 0)
> +		goto err_sysfs;
> +
> +	connector->encoder = encoder;
> +
> +	drm_object_property_set_value
> +		(&connector->base, fsl_dev->ddev->mode_config.dpms_property,
> +		DRM_MODE_DPMS_OFF);
> +
> +	return 0;
> +
> +err_sysfs:
> +	drm_connector_unregister(connector);
> +err_cleanup:
> +	drm_connector_cleanup(connector);
> +	return ret;
> +}
> diff --git a/drivers/gpu/drm/fsl/fsl_dcu_drm_connector.h
> b/drivers/gpu/drm/fsl/fsl_dcu_drm_connector.h
> new file mode 100644
> index 0000000..bbf6d38
> --- /dev/null
> +++ b/drivers/gpu/drm/fsl/fsl_dcu_drm_connector.h
> @@ -0,0 +1,30 @@
> +/*
> + * Copyright 2015 Freescale Semiconductor, Inc.
> + *
> + * Freescale DCU drm device driver
> + *
> + * 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 __FSL_DCU_DRM_CONNECTOR_H__
> +#define __FSL_DCU_DRM_CONNECTOR_H__
> +
> +#include <drm/drmP.h>
> +#include <drm/drm_crtc.h>
> +#include "fsl_dcu_drm_crtc.h"
> +
> +struct fsl_dcu_drm_device;
> +struct fsl_dcu_drm_connector {
> +	struct drm_connector connector;
> +	struct drm_encoder *encoder;
> +};
> +
> +int fsl_dcu_drm_encoder_create(struct fsl_dcu_drm_device *fsl_dev,
> +			       struct fsl_dcu_drm_crtc *crtc);
> +int fsl_dcu_drm_connector_create(struct fsl_dcu_drm_device *fsl_dev,
> +				 struct drm_encoder *encoder);
> +
> +#endif /* __FSL_DCU_DRM_CONNECTOR_H__ */
> diff --git a/drivers/gpu/drm/fsl/fsl_dcu_drm_crtc.c
> b/drivers/gpu/drm/fsl/fsl_dcu_drm_crtc.c
> new file mode 100644
> index 0000000..076e273
> --- /dev/null
> +++ b/drivers/gpu/drm/fsl/fsl_dcu_drm_crtc.c
> @@ -0,0 +1,165 @@
> +/*
> + * Copyright 2015 Freescale Semiconductor, Inc.
> + *
> + * Freescale DCU drm device driver
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License as published by
> + * the Free Software Foundation; either version 2 of the License, or
> + * (at your option) any later version.
> + */
> +
> +#include <linux/regmap.h>
> +#include <linux/clk.h>
> +
> +#include <drm/drmP.h>
> +#include <drm/drm_atomic.h>
> +#include <drm/drm_atomic_helper.h>
> +#include <drm/drm_crtc.h>
> +
> +#include "fsl_dcu_drm_crtc.h"
> +#include "fsl_dcu_drm_drv.h"
> +#include "fsl_dcu_drm_plane.h"
> +
> +#define to_fsl_dcu_crtc(c)	container_of(c, struct fsl_dcu_drm_crtc, crtc)
> +
> +void fsl_dcu_drm_crtc_suspend(struct drm_crtc *crtc)
> +{
> +}
> +
> +static void fsl_dcu_drm_crtc_mode_set_nofb(struct drm_crtc *crtc)
> +{
> +	struct drm_device *dev = crtc->dev;
> +	struct fsl_dcu_drm_device *fsl_dev = dev->dev_private;
> +	struct drm_display_mode *mode = &crtc->state->mode;
> +	uint32_t hbp, hfp, hsw, vbp, vfp, vsw, div, index;
> +
> +	DBG(": set mode: %d:\"%s\" %d %d %d %d %d %d %d %d %d %d 0x%x 0x%x",
> +	    mode->base.id, mode->name,
> +	    mode->vrefresh, mode->clock,
> +	    mode->hdisplay, mode->hsync_start,
> +	    mode->hsync_end, mode->htotal,
> +	    mode->vdisplay, mode->vsync_start,
> +	    mode->vsync_end, mode->vtotal,
> +	    mode->type, mode->flags);
> +
> +	index = drm_crtc_index(crtc);
> +	div = (uint32_t)clk_get_rate(fsl_dev->clk) / mode->clock / 1000;
> +
> +	/* Configure timings: */
> +	hbp = mode->htotal - mode->hsync_end;
> +	hfp = mode->hsync_start - mode->hdisplay;
> +	hsw = mode->hsync_end - mode->hsync_start;
> +	vbp = mode->vtotal - mode->vsync_end;
> +	vfp = mode->vsync_start - mode->vdisplay;
> +	vsw = mode->vsync_end - mode->vsync_start;
> +
> +	regmap_write(fsl_dev->regmap, DCU_HSYN_PARA,
> +		     DCU_HSYN_PARA_BP(hbp) |
> +		     DCU_HSYN_PARA_PW(hsw) |
> +		     DCU_HSYN_PARA_FP(hfp));
> +	regmap_write(fsl_dev->regmap, DCU_VSYN_PARA,
> +		     DCU_VSYN_PARA_BP(vbp) |
> +		     DCU_VSYN_PARA_PW(vsw) |
> +		     DCU_VSYN_PARA_FP(vfp));
> +	regmap_write(fsl_dev->regmap, DCU_DISP_SIZE,
> +		     DCU_DISP_SIZE_DELTA_Y(mode->vdisplay) |
> +		     DCU_DISP_SIZE_DELTA_X(mode->hdisplay));
> +	regmap_write(fsl_dev->regmap, DCU_DIV_RATIO, div);
> +	regmap_write(fsl_dev->regmap, DCU_UPDATE_MODE, DCU_UPDATE_MODE_READREG);
> +}
> +
> +static bool fsl_dcu_drm_crtc_mode_fixup(struct drm_crtc *crtc,
> +					const struct drm_display_mode *mode,
> +					struct drm_display_mode *adjusted_mode)
> +{
> +	return true;
> +}
> +
> +static void fsl_dcu_drm_crtc_prepare(struct drm_crtc *crtc)
> +{
> +}
> +
> +/* Now enable the clocks, plane, pipe, and connectors that we set up. */
> +static void fsl_dcu_drm_crtc_mode_commit(struct drm_crtc *crtc)
> +{
> +}
> +
> +static int fsl_dcu_drm_crtc_atomic_check(struct drm_crtc *crtc,
> +					 struct drm_crtc_state *state)
> +{
> +	return 0;
> +}
> +
> +static void fsl_dcu_drm_crtc_atomic_begin(struct drm_crtc *crtc)
> +{
> +}
> +
> +static void fsl_dcu_drm_crtc_atomic_flush(struct drm_crtc *crtc)
> +{
> +}
> +
> +static void fsl_dcu_drm_disable_crtc(struct drm_crtc *crtc)
> +{
> +}
> +
> +static const struct drm_crtc_funcs fsl_dcu_drm_crtc_funcs = {
> +	.page_flip = drm_atomic_helper_page_flip,
> +	.set_config = drm_atomic_helper_set_config,
> +	.destroy = drm_crtc_cleanup,
> +	.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 void fsl_dcu_drm_crtc_dpms(struct drm_crtc *crtc, int mode)
> +{
> +}
> +
> +static const struct drm_crtc_helper_funcs fsl_dcu_drm_crtc_helper_funcs = {
> +	.disable = fsl_dcu_drm_disable_crtc,
> +	.mode_fixup = fsl_dcu_drm_crtc_mode_fixup,
> +	.mode_set = drm_helper_crtc_mode_set,
> +	.mode_set_nofb = fsl_dcu_drm_crtc_mode_set_nofb,
> +	.mode_set_base = drm_helper_crtc_mode_set_base,
> +	.prepare = fsl_dcu_drm_crtc_prepare,
> +	.commit = fsl_dcu_drm_crtc_mode_commit,
> +	.atomic_check = fsl_dcu_drm_crtc_atomic_check,
> +	.atomic_begin = fsl_dcu_drm_crtc_atomic_begin,
> +	.atomic_flush = fsl_dcu_drm_crtc_atomic_flush,
> +	.dpms = fsl_dcu_drm_crtc_dpms,
> +};
> +
> +int fsl_dcu_drm_crtc_create(struct fsl_dcu_drm_device *fsl_dev)
> +{
> +	struct drm_plane *primary;
> +	struct drm_crtc *crtc = &fsl_dev->crtc.crtc;
> +	int ret;
> +
> +	fsl_dev->crtc.dpms = DRM_MODE_DPMS_OFF;
> +
> +	primary = fsl_dcu_drm_primary_create_plane(fsl_dev->ddev);
> +	ret = drm_crtc_init_with_planes(fsl_dev->ddev, crtc, primary, NULL,
> +					&fsl_dcu_drm_crtc_funcs);
> +	if (ret < 0)
> +		return ret;
> +
> +	drm_crtc_helper_add(crtc, &fsl_dcu_drm_crtc_helper_funcs);
> +
> +	regmap_write(fsl_dev->regmap, DCU_SYN_POL,
> +		     DCU_SYN_POL_INV_VS_LOW | DCU_SYN_POL_INV_HS_LOW);
> +	regmap_write(fsl_dev->regmap, DCU_BGND, DCU_BGND_R(0) |
> +		     DCU_BGND_G(0) | DCU_BGND_B(0));
> +	regmap_write(fsl_dev->regmap, DCU_DCU_MODE,
> +		     DCU_MODE_BLEND_ITER(1) | DCU_MODE_RASTER_EN);
> +	regmap_write(fsl_dev->regmap, DCU_THRESHOLD,
> +		     DCU_THRESHOLD_LS_BF_VS(BF_VS_VAL) |
> +		     DCU_THRESHOLD_OUT_BUF_HIGH(BUF_MAX_VAL) |
> +		     DCU_THRESHOLD_OUT_BUF_LOW(BUF_MIN_VAL));
> +	regmap_update_bits(fsl_dev->regmap, DCU_DCU_MODE,
> +			   DCU_MODE_DCU_MODE_MASK,
> +			   DCU_MODE_DCU_MODE(DCU_MODE_OFF));
> +	regmap_write(fsl_dev->regmap, DCU_UPDATE_MODE, DCU_UPDATE_MODE_READREG);
> +
> +	return 0;
> +}
> diff --git a/drivers/gpu/drm/fsl/fsl_dcu_drm_crtc.h
> b/drivers/gpu/drm/fsl/fsl_dcu_drm_crtc.h
> new file mode 100644
> index 0000000..d44b564
> --- /dev/null
> +++ b/drivers/gpu/drm/fsl/fsl_dcu_drm_crtc.h
> @@ -0,0 +1,26 @@
> +/*
> + * Copyright 2015 Freescale Semiconductor, Inc.
> + *
> + * Freescale DCU drm device driver
> + *
> + * 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 __FSL_DCU_DRM_CRTC_H__
> +#define __FSL_DCU_DRM_CRTC_H__
> +
> +#include <drm/drmP.h>
> +#include <drm/drm_crtc.h>
> +
> +struct fsl_dcu_drm_device;
> +struct fsl_dcu_drm_crtc {
> +	struct drm_crtc crtc;
> +	int dpms;
> +};
> +
> +int fsl_dcu_drm_crtc_create(struct fsl_dcu_drm_device *fsl_dev);
> +
> +#endif /* __FSL_DCU_DRM_CRTC_H__ */
> diff --git a/drivers/gpu/drm/fsl/fsl_dcu_drm_drv.c
> b/drivers/gpu/drm/fsl/fsl_dcu_drm_drv.c
> new file mode 100644
> index 0000000..d4a559a
> --- /dev/null
> +++ b/drivers/gpu/drm/fsl/fsl_dcu_drm_drv.c
> @@ -0,0 +1,331 @@
> +/*
> + * Copyright 2015 Freescale Semiconductor, Inc.
> + *
> + * Freescale DCU drm device driver
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License as published by
> + * the Free Software Foundation; either version 2 of the License, or
> + * (at your option) any later version.
> + */
> +
> +#include <linux/clk.h>
> +#include <linux/io.h>
> +#include <linux/mm.h>
> +#include <linux/module.h>
> +#include <linux/of_platform.h>
> +#include <linux/platform_device.h>
> +#include <linux/pm.h>
> +#include <linux/pm_runtime.h>
> +#include <linux/regmap.h>
> +
> +#include <drm/drmP.h>
> +#include <linux/fsl/dcu.h>

This file seems to be missing in that patch.

> +
> +#include "fsl_dcu_drm_drv.h"
> +#include "fsl_dcu_drm_kms.h"
> +
> +static int fsl_dcu_unload(struct drm_device *dev)
> +{
> +	drm_mode_config_cleanup(dev);
> +	drm_vblank_cleanup(dev);
> +	drm_irq_uninstall(dev);
> +
> +	dev->dev_private = NULL;
> +
> +	return 0;
> +}
> +
> +static struct regmap_config fsl_dcu_regmap_config = {
> +	.reg_bits = 32,
> +	.reg_stride = 4,
> +	.val_bits = 32,
> +};
> +
> +static int fsl_dcu_bypass_tcon(struct fsl_dcu_drm_device *fsl_dev,
> +			       struct device_node *np)
> +{
> +	struct device_node *tcon_np;
> +	struct platform_device *pdev;
> +	struct clk *tcon_clk;
> +	struct resource *res;
> +	void __iomem *base;
> +
> +	tcon_np = of_parse_phandle(np, "tcon-controller", 0);
> +	if (!tcon_np)
> +		return -EINVAL;
> +
> +	pdev = of_find_device_by_node(tcon_np);
> +	if (!pdev)
> +		return -EINVAL;
> +
> +	tcon_clk = devm_clk_get(&pdev->dev, "tcon");
> +	if (IS_ERR(tcon_clk))
> +		return PTR_ERR(tcon_clk);
> +	clk_prepare_enable(tcon_clk);

You enable the clock explicitly...

> +
> +	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> +	if (!res)
> +		return -ENODEV;
> +
> +	base = devm_ioremap_resource(&pdev->dev, res);
> +	if (IS_ERR(base))
> +		return PTR_ERR(base);
> +
> +	fsl_dev->tcon_regmap = devm_regmap_init_mmio_clk(&pdev->dev,
> +			"tcon", base, &fsl_dcu_regmap_config);

And implicitly using regmap. In a short test on Vybrid, the clock is
actually not needed during operation, hence we could use the explicit
enabling above, what do you think?

Also, the clock and tcon in general currently does not get handled by
suspend/resume code...

> +	if (IS_ERR(fsl_dev->tcon_regmap)) {
> +		dev_err(&pdev->dev, "regmap init failed\n");
> +		return PTR_ERR(fsl_dev->tcon_regmap);
> +	}
> +
> +	regmap_write(fsl_dev->tcon_regmap, TCON_CTRL1, TCON_BYPASS_ENABLE);
> +	return 0;
> +}
> +
> +static int fsl_dcu_drm_irq_init(struct drm_device *dev)
> +{
> +	struct platform_device *pdev = dev->platformdev;
> +	struct fsl_dcu_drm_device *fsl_dev = dev->dev_private;
> +	unsigned int int_mask;
> +	int ret;
> +
> +	ret = drm_irq_install(dev, platform_get_irq(dev->platformdev, 0));
> +	if (ret < 0)
> +		dev_err(&pdev->dev, "failed to install IRQ handler\n");
> +
> +	dev->irq_enabled = true;
> +	dev->vblank_disable_allowed = true;
> +
> +	regmap_write(fsl_dev->regmap, DCU_INT_STATUS, 0);
> +	regmap_read(fsl_dev->regmap, DCU_INT_MASK, &int_mask);
> +	regmap_write(fsl_dev->regmap, DCU_INT_MASK, int_mask &
> +		     ~DCU_INT_MASK_VBLANK);
> +	regmap_write(fsl_dev->regmap, DCU_UPDATE_MODE, DCU_UPDATE_MODE_READREG);
> +
> +	return 0;
> +}
> +
> +static int fsl_dcu_load(struct drm_device *dev, unsigned long flags)
> +{
> +	struct platform_device *pdev = dev->platformdev;
> +	struct fsl_dcu_drm_device *fsl_dev;
> +	struct resource *res;
> +	void __iomem *base;
> +	int ret;
> +
> +	fsl_dev = devm_kzalloc(&pdev->dev, sizeof(*fsl_dev), GFP_KERNEL);
> +	if (!fsl_dev)
> +		return -ENOMEM;
> +
> +	fsl_dev->dev = &pdev->dev;
> +	fsl_dev->ddev = dev;
> +	fsl_dev->np = pdev->dev.of_node;
> +	dev->dev_private = fsl_dev;
> +	drm_dev_set_unique(dev, dev_name(dev->dev));
> +
> +	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> +	if (!res) {
> +		dev_err(&pdev->dev, "could not get memory IO resource\n");
> +		return -ENODEV;
> +	}
> +
> +	base = devm_ioremap_resource(&pdev->dev, res);
> +	if (IS_ERR(base)) {
> +		ret = PTR_ERR(base);
> +		return ret;
> +	}
> +
> +	fsl_dev->regmap = devm_regmap_init_mmio_clk(&pdev->dev, NULL,
> +			base, &fsl_dcu_regmap_config);
> +	if (IS_ERR(fsl_dev->regmap)) {
> +		dev_err(&pdev->dev, "regmap init failed\n");
> +		return PTR_ERR(fsl_dev->regmap);
> +	}
> +
> +	/* Put TCON in bypass mode, so the input signals from DCU are passed
> +	 * through TCON unchanged */
> +	fsl_dcu_bypass_tcon(fsl_dev, fsl_dev->np);
> +	fsl_dev->clk = devm_clk_get(&pdev->dev, "dcu");
> +	if (IS_ERR(fsl_dev->clk)) {
> +		ret = PTR_ERR(fsl_dev->clk);
> +		dev_err(&pdev->dev, "could not get clock\n");
> +		return ret;
> +	}
> +	clk_prepare_enable(fsl_dev->clk);
> +	dev_set_drvdata(dev->dev, fsl_dev);
> +
> +	ret = fsl_dcu_drm_modeset_init(fsl_dev);
> +	if (ret < 0) {
> +		dev_err(&pdev->dev, "failed to initialize mode setting\n");
> +		return ret;
> +	}
> +
> +	ret = drm_vblank_init(dev, dev->mode_config.num_crtc);
> +	if (ret < 0) {
> +		dev_err(&pdev->dev, "failed to initialize vblank\n");
> +		goto done;
> +	}
> +
> +	ret = fsl_dcu_drm_irq_init(dev);
> +	if (ret < 0)
> +		goto done;
> +
> +	fsl_dcu_fbdev_init(dev);
> +
> +	return 0;
> +done:
> +	if (ret)
> +		fsl_dcu_unload(dev);
> +
> +	return ret;
> +}
> +
> +static void fsl_dcu_drm_preclose(struct drm_device *dev, struct drm_file *file)
> +{
> +	;
> +}
> +
> +static irqreturn_t fsl_dcu_drm_irq(int irq, void *arg)
> +{
> +	struct drm_device *dev = arg;
> +	struct fsl_dcu_drm_device *fsl_dev = dev->dev_private;
> +	unsigned int int_status;
> +
> +	regmap_read(fsl_dev->regmap, DCU_INT_STATUS, &int_status);
> +	if (int_status & DCU_INT_STATUS_VBLANK)
> +		drm_handle_vblank(dev, 0);
> +
> +	regmap_write(fsl_dev->regmap, DCU_INT_STATUS, 0xffffffff);
> +	regmap_write(fsl_dev->regmap, DCU_UPDATE_MODE, DCU_UPDATE_MODE_READREG);
> +
> +	return IRQ_HANDLED;
> +}
> +
> +static int fsl_dcu_drm_enable_vblank(struct drm_device *dev, int crtc)
> +{
> +	return 0;
> +}
> +
> +static void fsl_dcu_drm_disable_vblank(struct drm_device *dev, int crtc)
> +{
> +	;
> +}
> +
> +static const struct file_operations fsl_dcu_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		= no_llseek,
> +	.mmap		= drm_gem_cma_mmap,
> +};
> +
> +static struct drm_driver fsl_dcu_drm_driver = {
> +	.driver_features	= DRIVER_HAVE_IRQ | DRIVER_GEM | DRIVER_MODESET
> +				| DRIVER_PRIME,
> +	.load			= fsl_dcu_load,
> +	.unload			= fsl_dcu_unload,
> +	.preclose		= fsl_dcu_drm_preclose,
> +	.irq_handler		= fsl_dcu_drm_irq,
> +	.get_vblank_counter	= drm_vblank_count,
> +	.enable_vblank		= fsl_dcu_drm_enable_vblank,
> +	.disable_vblank		= fsl_dcu_drm_disable_vblank,
> +	.gem_free_object	= drm_gem_cma_free_object,
> +	.gem_vm_ops		= &drm_gem_cma_vm_ops,
> +	.prime_handle_to_fd	= drm_gem_prime_handle_to_fd,
> +	.prime_fd_to_handle	= drm_gem_prime_fd_to_handle,
> +	.gem_prime_import	= drm_gem_prime_import,
> +	.gem_prime_export	= drm_gem_prime_export,
> +	.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,
> +	.dumb_create		= drm_gem_cma_dumb_create,
> +	.dumb_map_offset	= drm_gem_cma_dumb_map_offset,
> +	.dumb_destroy		= drm_gem_dumb_destroy,
> +	.fops			= &fsl_dcu_drm_fops,
> +	.name			= "fsl-dcu-drm",
> +	.desc			= "Freescale DCU DRM",
> +	.date			= "20150213",
> +	.major			= 1,
> +	.minor			= 0,
> +};
> +
> +#ifdef CONFIG_PM_SLEEP
> +static int fsl_dcu_drm_pm_suspend(struct device *dev)
> +{
> +	struct fsl_dcu_drm_device *fsl_dev = dev_get_drvdata(dev);
> +
> +	if (of_device_is_compatible(fsl_dev->np, "fsl,ls1021a-dcu"))
> +		dcu_pixclk_disable();
> +
> +	drm_kms_helper_poll_disable(fsl_dev->ddev);
> +	fsl_dcu_drm_crtc_suspend(&fsl_dev->crtc);

I get

drivers/gpu/drm/fsl/fsl_dcu_drm_drv.c: In function
'fsl_dcu_drm_pm_suspend':
drivers/gpu/drm/fsl/fsl_dcu_drm_drv.c:270:2: error: implicit declaration
of function 'fsl_dcu_drm_crtc_suspend'
[-Werror=implicit-function-declaration]
  fsl_dcu_drm_crtc_suspend(&fsl_dev->crtc);
  ^
drivers/gpu/drm/fsl/fsl_dcu_drm_drv.c: In function
'fsl_dcu_drm_pm_resume':
drivers/gpu/drm/fsl/fsl_dcu_drm_drv.c:280:2: error: implicit declaration
of function 'fsl_dcu_drm_crtc_resume'
[-Werror=implicit-function-declaration]
  fsl_dcu_drm_crtc_resume(&fsl_dev->crtc);
  ^

The function fsl_dcu_drm_crtc_suspend seems to be part of
fsl_dcu_drm_crtc.c, but is empty. While the other is missing
completely... Please fix/remove as appropriate.

> +
> +	return 0;
> +}
> +
> +static int fsl_dcu_drm_pm_resume(struct device *dev)
> +{
> +	struct fsl_dcu_drm_device *fsl_dev = dev_get_drvdata(dev);
> +
> +	drm_modeset_lock_all(fsl_dev->ddev);
> +	fsl_dcu_drm_crtc_resume(&fsl_dev->crtc);
> +	drm_modeset_unlock_all(fsl_dev->ddev);
> +	drm_kms_helper_poll_enable(fsl_dev->ddev);
> +
> +	if (of_device_is_compatible(fsl_dev->np, "fsl,ls1021a-dcu"))
> +		dcu_pixclk_enable();
> +
> +	return 0;
> +}
> +#endif
> +
> +static const struct dev_pm_ops fsl_dcu_drm_pm_ops = {
> +	SET_SYSTEM_SLEEP_PM_OPS(fsl_dcu_drm_pm_suspend, fsl_dcu_drm_pm_resume)
> +};
> +
> +static int fsl_dcu_drm_probe(struct platform_device *pdev)
> +{
> +	return drm_platform_init(&fsl_dcu_drm_driver, pdev);
> +}
> +
> +static int fsl_dcu_drm_remove(struct platform_device *pdev)
> +{
> +	struct fsl_dcu_drm_device *fsl_dev = platform_get_drvdata(pdev);
> +
> +	drm_put_dev(fsl_dev->ddev);
> +
> +	return 0;
> +}
> +
> +static const struct of_device_id fsl_dcu_of_match[] = {
> +		{ .compatible = "fsl,ls1021a-dcu", },
> +		{ .compatible = "fsl,vf610-dcu", },
> +		{ },
> +};
> +MODULE_DEVICE_TABLE(of, fsl_dcu_of_match);
> +
> +static struct platform_driver fsl_dcu_drm_platform_driver = {
> +	.probe		= fsl_dcu_drm_probe,
> +	.remove		= fsl_dcu_drm_remove,
> +	.driver		= {
> +		.owner	= THIS_MODULE,
> +		.name	= "fsl,dcu",
> +		.pm	= &fsl_dcu_drm_pm_ops,
> +		.of_match_table = fsl_dcu_of_match,
> +	},
> +};
> +
> +module_platform_driver(fsl_dcu_drm_platform_driver);
> +
> +MODULE_ALIAS("platform:fsl-dcu-drm");
> +MODULE_DESCRIPTION("Freescale DCU DRM Driver");
> +MODULE_LICENSE("GPL");
> diff --git a/drivers/gpu/drm/fsl/fsl_dcu_drm_drv.h
> b/drivers/gpu/drm/fsl/fsl_dcu_drm_drv.h
> new file mode 100644
> index 0000000..27226109
> --- /dev/null
> +++ b/drivers/gpu/drm/fsl/fsl_dcu_drm_drv.h
> @@ -0,0 +1,210 @@
> +/*
> + * Copyright 2015 Freescale Semiconductor, Inc.
> + *
> + * Freescale DCU drm device driver
> + *
> + * 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 __FSL_DCU_DRM_DRV_H__
> +#define __FSL_DCU_DRM_DRV_H__
> +
> +#include <linux/kernel.h>
> +#include <linux/spinlock.h>
> +#include <stddef.h>
> +#include <drm/drm.h>
> +#include <drm/drmP.h>
> +#include <drm/drm_fb_helper.h>
> +#include <drm/drm_crtc_helper.h>
> +#include <drm/drm_gem_cma_helper.h>
> +#include <drm/drm_fb_cma_helper.h>
> +
> +#include "fsl_dcu_drm_crtc.h"
> +#include "fsl_dcu_drm_plane.h"
> +#include "fsl_dcu_drm_connector.h"
> +#define DRIVER_NAME			"fsl-dcu-drm"
> +
> +#define DCU_DCU_MODE			0x0010
> +#define DCU_MODE_BLEND_ITER(x)		((x) << 20)
> +#define DCU_MODE_RASTER_EN		BIT(14)
> +#define DCU_MODE_DCU_MODE(x)		(x)
> +#define DCU_MODE_DCU_MODE_MASK		0x03
> +#define DCU_MODE_OFF			0
> +#define DCU_MODE_NORMAL			1
> +#define DCU_MODE_TEST			2
> +#define DCU_MODE_COLORBAR		3
> +
> +#define DCU_BGND			0x0014
> +#define DCU_BGND_R(x)			((x) << 16)
> +#define DCU_BGND_G(x)			((x) << 8)
> +#define DCU_BGND_B(x)			(x)
> +
> +#define DCU_DISP_SIZE			0x0018
> +#define DCU_DISP_SIZE_DELTA_Y(x)	((x) << 16)
> +/*Regisiter value 1/16 of horizontal resolution*/
> +#define DCU_DISP_SIZE_DELTA_X(x)	((x) >> 4)
> +
> +#define DCU_HSYN_PARA			0x001c
> +#define DCU_HSYN_PARA_BP(x)		((x) << 22)
> +#define DCU_HSYN_PARA_PW(x)		((x) << 11)
> +#define DCU_HSYN_PARA_FP(x)		(x)
> +
> +#define DCU_VSYN_PARA			0x0020
> +#define DCU_VSYN_PARA_BP(x)		((x) << 22)
> +#define DCU_VSYN_PARA_PW(x)		((x) << 11)
> +#define DCU_VSYN_PARA_FP(x)		(x)
> +
> +#define DCU_SYN_POL			0x0024
> +#define DCU_SYN_POL_INV_PXCK_FALL	(0 << 6)
> +#define DCU_SYN_POL_NEG_REMAIN		(0 << 5)
> +#define DCU_SYN_POL_INV_VS_LOW		BIT(1)
> +#define DCU_SYN_POL_INV_HS_LOW		BIT(0)
> +
> +#define DCU_THRESHOLD			0x0028
> +#define DCU_THRESHOLD_LS_BF_VS(x)	((x) << 16)
> +#define DCU_THRESHOLD_OUT_BUF_HIGH(x)	((x) << 8)
> +#define DCU_THRESHOLD_OUT_BUF_LOW(x)	(x)
> +#define BF_VS_VAL			0x03
> +#define BUF_MAX_VAL			0x78
> +#define BUF_MIN_VAL			0x0a
> +
> +#define DCU_INT_STATUS			0x002C
> +#define DCU_INT_STATUS_VSYNC		BIT(0)
> +#define DCU_INT_STATUS_UNDRUN		BIT(1)
> +#define DCU_INT_STATUS_LSBFVS		BIT(2)
> +#define DCU_INT_STATUS_VBLANK		BIT(3)
> +#define DCU_INT_STATUS_CRCREADY		BIT(4)
> +#define DCU_INT_STATUS_CRCOVERFLOW	BIT(5)
> +#define DCU_INT_STATUS_P1FIFOLO		BIT(6)
> +#define DCU_INT_STATUS_P1FIFOHI		BIT(7)
> +#define DCU_INT_STATUS_P2FIFOLO		BIT(8)
> +#define DCU_INT_STATUS_P2FIFOHI		BIT(9)
> +#define DCU_INT_STATUS_PROGEND		BIT(10)
> +#define DCU_INT_STATUS_IPMERROR		BIT(11)
> +#define DCU_INT_STATUS_LYRTRANS		BIT(12)
> +#define DCU_INT_STATUS_DMATRANS		BIT(14)
> +#define DCU_INT_STATUS_P3FIFOLO		BIT(16)
> +#define DCU_INT_STATUS_P3FIFOHI		BIT(17)
> +#define DCU_INT_STATUS_P4FIFOLO		BIT(18)
> +#define DCU_INT_STATUS_P4FIFOHI		BIT(19)
> +#define DCU_INT_STATUS_P1EMPTY		BIT(26)
> +#define DCU_INT_STATUS_P2EMPTY		BIT(27)
> +#define DCU_INT_STATUS_P3EMPTY		BIT(28)
> +#define DCU_INT_STATUS_P4EMPTY		BIT(29)
> +
> +#define DCU_INT_MASK			0x0030
> +#define DCU_INT_MASK_VSYNC		BIT(0)
> +#define DCU_INT_MASK_UNDRUN		BIT(1)
> +#define DCU_INT_MASK_LSBFVS		BIT(2)
> +#define DCU_INT_MASK_VBLANK		BIT(3)
> +#define DCU_INT_MASK_CRCREADY		BIT(4)
> +#define DCU_INT_MASK_CRCOVERFLOW	BIT(5)
> +#define DCU_INT_MASK_P1FIFOLO		BIT(6)
> +#define DCU_INT_MASK_P1FIFOHI		BIT(7)
> +#define DCU_INT_MASK_P2FIFOLO		BIT(8)
> +#define DCU_INT_MASK_P2FIFOHI		BIT(9)
> +#define DCU_INT_MASK_PROGEND		BIT(10)
> +#define DCU_INT_MASK_IPMERROR		BIT(11)
> +#define DCU_INT_MASK_LYRTRANS		BIT(12)
> +#define DCU_INT_MASK_DMATRANS		BIT(14)
> +#define DCU_INT_MASK_P3FIFOLO		BIT(16)
> +#define DCU_INT_MASK_P3FIFOHI		BIT(17)
> +#define DCU_INT_MASK_P4FIFOLO		BIT(18)
> +#define DCU_INT_MASK_P4FIFOHI		BIT(19)
> +#define DCU_INT_MASK_P1EMPTY		BIT(26)
> +#define DCU_INT_MASK_P2EMPTY		BIT(27)
> +#define DCU_INT_MASK_P3EMPTY		BIT(28)
> +#define DCU_INT_MASK_P4EMPTY		BIT(29)
> +
> +#define DCU_DIV_RATIO			0x0054
> +
> +#define DCU_UPDATE_MODE			0x00cc
> +#define DCU_UPDATE_MODE_MODE		BIT(31)
> +#define DCU_UPDATE_MODE_READREG		BIT(30)
> +
> +#define DCU_DCFB_MAX			0x300
> +
> +#define DCU_CTRLDESCLN_1(x)		(0x200 + (x) * 0x40)
> +#define DCU_CTRLDESCLN_1_HEIGHT(x)	((x) << 16)
> +#define DCU_CTRLDESCLN_1_WIDTH(x)	(x)
> +
> +#define DCU_CTRLDESCLN_2(x)		(0x204 + (x) * 0x40)
> +#define DCU_CTRLDESCLN_2_POSY(x)	((x) << 16)
> +#define DCU_CTRLDESCLN_2_POSX(x)	(x)
> +
> +#define DCU_CTRLDESCLN_3(x)		(0x208 + (x) * 0x40)
> +
> +#define DCU_CTRLDESCLN_4(x)		(0x20c + (x) * 0x40)
> +#define DCU_CTRLDESCLN_4_EN		BIT(31)
> +#define DCU_CTRLDESCLN_4_TILE_EN	BIT(30)
> +#define DCU_CTRLDESCLN_4_DATA_SEL_CLUT	BIT(29)
> +#define DCU_CTRLDESCLN_4_SAFETY_EN	BIT(28)
> +#define DCU_CTRLDESCLN_4_TRANS(x)	((x) << 20)
> +#define DCU_CTRLDESCLN_4_BPP(x)		((x) << 16)
> +#define DCU_CTRLDESCLN_4_RLE_EN		BIT(15)
> +#define DCU_CTRLDESCLN_4_LUOFFS(x)	((x) << 4)
> +#define DCU_CTRLDESCLN_4_BB_ON		BIT(2)
> +#define DCU_CTRLDESCLN_4_AB(x)		(x)
> +
> +#define DCU_CTRLDESCLN_5(x)		(0x210 + (x) * 0x40)
> +#define DCU_CTRLDESCLN_5_CKMAX_R(x)	((x) << 16)
> +#define DCU_CTRLDESCLN_5_CKMAX_G(x)	((x) << 8)
> +#define DCU_CTRLDESCLN_5_CKMAX_B(x)	(x)
> +
> +#define DCU_CTRLDESCLN_6(x)		(0x214 + (x) * 0x40)
> +#define DCU_CTRLDESCLN_6_CKMIN_R(x)	((x) << 16)
> +#define DCU_CTRLDESCLN_6_CKMIN_G(x)	((x) << 8)
> +#define DCU_CTRLDESCLN_6_CKMIN_B(x)	(x)
> +
> +#define DCU_CTRLDESCLN_7(x)		(0x218 + (x) * 0x40)
> +#define DCU_CTRLDESCLN_7_TILE_VER(x)	((x) << 16)
> +#define DCU_CTRLDESCLN_7_TILE_HOR(x)	(x)
> +
> +#define DCU_CTRLDESCLN_8(x)		(0x21c + (x) * 0x40)
> +#define DCU_CTRLDESCLN_8_FG_FCOLOR(x)	(x)
> +
> +#define DCU_CTRLDESCLN_9(x)		(0x220 + (x) * 0x40)
> +#define DCU_CTRLDESCLN_9_BG_BCOLOR(x)	(x)
> +
> +#define DCU_CTRLDESCLN_10(x)		(0x224 + (x) * 0x40)
> +#define DCU_CTRLDESCLN_10_POST_SKIP(x)	((x) << 16)
> +#define DCU_CTRLDESCLN_10_PRE_SKIP(x)	(x)
> +
> +#define FSL_DCU_RGB565			4
> +#define FSL_DCU_RGB888			5
> +#define FSL_DCU_ARGB8888		6
> +#define FSL_DCU_ARGB1555		11
> +#define FSL_DCU_ARGB4444		12
> +#define FSL_DCU_YUV422			14
> +
> +#define TCON_CTRL1			0x0000
> +#define TCON_BYPASS_ENABLE		BIT(29)
> +
> +#define DBG(fmt, ...) DRM_DEBUG(fmt"\n", ##__VA_ARGS__)
> +
> +struct clk;
> +struct device;
> +struct drm_device;
> +
> +struct fsl_dcu_drm_device {
> +	struct device *dev;
> +	struct device_node *np;
> +	struct regmap *regmap;
> +	struct regmap *tcon_regmap;
> +	unsigned int irq;
> +	struct clk *clk;
> +	/*protects hardware register*/
> +	spinlock_t irq_lock;
> +	struct drm_device *ddev;
> +	struct drm_fbdev_cma *fbdev;
> +	struct fsl_dcu_drm_crtc crtc;
> +	struct drm_encoder encoder;
> +	struct fsl_dcu_drm_connector connector;
> +};
> +
> +void fsl_dcu_fbdev_init(struct drm_device *dev);
> +
> +#endif /* __FSL_DCU_DRM_DRV_H__ */
> diff --git a/drivers/gpu/drm/fsl/fsl_dcu_drm_fbdev.c
> b/drivers/gpu/drm/fsl/fsl_dcu_drm_fbdev.c
> new file mode 100644
> index 0000000..f8ef0e1
> --- /dev/null
> +++ b/drivers/gpu/drm/fsl/fsl_dcu_drm_fbdev.c
> @@ -0,0 +1,26 @@
> +/*
> + * Copyright 2015 Freescale Semiconductor, Inc.
> + *
> + * 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.
> + *
> + * This program is distributed in the hope that it will be useful, but WITHOUT
> + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
> + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
> + * more details.
> + *
> + */
> +
> +#include <drm/drmP.h>
> +#include <drm/drm_fb_cma_helper.h>
> +
> +#include "fsl_dcu_drm_drv.h"
> +
> +/* initialize fbdev helper */
> +void fsl_dcu_fbdev_init(struct drm_device *dev)
> +{
> +	struct fsl_dcu_drm_device *fsl_dev = dev_get_drvdata(dev->dev);
> +
> +	fsl_dev->fbdev = drm_fbdev_cma_init(dev, 24, 1, 1);
> +}
> diff --git a/drivers/gpu/drm/fsl/fsl_dcu_drm_kms.c
> b/drivers/gpu/drm/fsl/fsl_dcu_drm_kms.c
> new file mode 100644
> index 0000000..0de21c6
> --- /dev/null
> +++ b/drivers/gpu/drm/fsl/fsl_dcu_drm_kms.c
> @@ -0,0 +1,42 @@
> +/*
> + * Copyright 2015 Freescale Semiconductor, Inc.
> + *
> + * Freescale DCU drm device driver
> + *
> + * 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 "fsl_dcu_drm_crtc.h"
> +#include "fsl_dcu_drm_connector.h"
> +#include "fsl_dcu_drm_drv.h"
> +
> +static const struct drm_mode_config_funcs fsl_dcu_drm_mode_config_funcs = {
> +	.fb_create = drm_fb_cma_create,
> +	.atomic_check = drm_atomic_helper_check,
> +	.atomic_commit = drm_atomic_helper_commit,
> +};
> +
> +int fsl_dcu_drm_modeset_init(struct fsl_dcu_drm_device *fsl_dev)
> +{
> +	drm_mode_config_init(fsl_dev->ddev);
> +
> +	fsl_dev->ddev->mode_config.min_width = 0;
> +	fsl_dev->ddev->mode_config.min_height = 0;
> +	fsl_dev->ddev->mode_config.max_width = 2031;
> +	fsl_dev->ddev->mode_config.max_height = 2047;
> +	fsl_dev->ddev->mode_config.funcs = &fsl_dcu_drm_mode_config_funcs;
> +
> +	drm_kms_helper_poll_init(fsl_dev->ddev);
> +	fsl_dcu_drm_crtc_create(fsl_dev);
> +	fsl_dcu_drm_encoder_create(fsl_dev, &fsl_dev->crtc);
> +	fsl_dcu_drm_connector_create(fsl_dev, &fsl_dev->encoder);
> +	drm_mode_config_reset(fsl_dev->ddev);
> +
> +	return 0;
> +}
> diff --git a/drivers/gpu/drm/fsl/fsl_dcu_drm_kms.h
> b/drivers/gpu/drm/fsl/fsl_dcu_drm_kms.h
> new file mode 100644
> index 0000000..b9bd299
> --- /dev/null
> +++ b/drivers/gpu/drm/fsl/fsl_dcu_drm_kms.h
> @@ -0,0 +1,17 @@
> +/*
> + * Copyright 2015 Freescale Semiconductor, Inc.
> + *
> + * Freescale DCU drm device driver
> + *
> + * 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 __FSL_DCU_DRM_KMS_H__
> +#define __FSL_DCU_DRM_KMS_H__
> +
> +int fsl_dcu_drm_modeset_init(struct fsl_dcu_drm_device *fsl_dev);
> +
> +#endif /* __FSL_DCU_DRM_KMS_H__ */
> diff --git a/drivers/gpu/drm/fsl/fsl_dcu_drm_plane.c
> b/drivers/gpu/drm/fsl/fsl_dcu_drm_plane.c
> new file mode 100644
> index 0000000..6146e80
> --- /dev/null
> +++ b/drivers/gpu/drm/fsl/fsl_dcu_drm_plane.c
> @@ -0,0 +1,192 @@
> +/*
> + * Copyright 2015 Freescale Semiconductor, Inc.
> + *
> + * Freescale DCU drm device driver
> + *
> + * 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_crtc.h>
> +#include <drm/drm_crtc_helper.h>
> +#include <drm/drm_fb_cma_helper.h>
> +#include <drm/drm_gem_cma_helper.h>
> +#include <linux/regmap.h>
> +#include <drm/drm_plane_helper.h>
> +#include <drm/drm_atomic_helper.h>
> +
> +#include "fsl_dcu_drm_drv.h"
> +#include "fsl_dcu_drm_kms.h"
> +#include "fsl_dcu_drm_plane.h"
> +
> +#define to_fsl_dcu_plane(plane) \
> +	container_of(plane, struct fsl_dcu_drm_plane, plane)
> +
> +static int
> +fsl_dcu_drm_plane_prepare_fb(struct drm_plane *plane,
> +			     struct drm_framebuffer *fb,
> +			     const struct drm_plane_state *new_state)
> +{
> +	return 0;
> +}
> +
> +static void
> +fsl_dcu_drm_plane_cleanup_fb(struct drm_plane *plane,
> +			     struct drm_framebuffer *fb,
> +			     const struct drm_plane_state *new_state)
> +{
> +}
> +
> +static int fsl_dcu_drm_plane_atomic_check(struct drm_plane *plane,
> +					  struct drm_plane_state *state)
> +{
> +	return 0;
> +}
> +
> +static void fsl_dcu_drm_plane_atomic_disable(struct drm_plane *plane,
> +					     struct drm_plane_state *old_state)
> +{
> +}
> +
> +void fsl_dcu_drm_plane_atomic_update(struct drm_plane *plane,
> +				     struct drm_plane_state *old_state)
> +{
> +	struct fsl_dcu_drm_device *fsl_dev = plane->dev->dev_private;
> +	struct drm_plane_state *state = plane->state;
> +	struct drm_framebuffer *fb = plane->state->fb;
> +	u32 index, alpha, bpp;
> +	struct drm_gem_cma_object *gem;
> +	struct fsl_dcu_drm_plane *fsl_plane = to_fsl_dcu_plane(plane);
> +
> +	index = fsl_plane->index;
> +	gem = drm_fb_cma_get_gem_obj(fb, 0);
> +
> +	switch (fb->pixel_format) {
> +	case DRM_FORMAT_RGB565:
> +		bpp = FSL_DCU_RGB565;
> +		alpha = 0xff;
> +		break;
> +	case DRM_FORMAT_RGB888:
> +		bpp = FSL_DCU_RGB888;
> +		alpha = 0xff;
> +		break;
> +	case DRM_FORMAT_ARGB8888:
> +		bpp = FSL_DCU_ARGB8888;
> +		alpha = 0xff;
> +		break;
> +	case DRM_FORMAT_BGRA4444:
> +		bpp = FSL_DCU_ARGB4444;
> +		alpha = 0xff;
> +		break;
> +	case DRM_FORMAT_ARGB1555:
> +		bpp = FSL_DCU_ARGB1555;
> +		alpha = 0xff;
> +		break;
> +	case DRM_FORMAT_YUV422:
> +		bpp = FSL_DCU_YUV422;
> +		alpha = 0xff;
> +		break;
> +	default:
> +		return;
> +	}
> +
> +	regmap_write(fsl_dev->regmap, DCU_CTRLDESCLN_1(index),
> +		     DCU_CTRLDESCLN_1_HEIGHT(state->crtc_h) |
> +		     DCU_CTRLDESCLN_1_WIDTH(state->crtc_w));
> +	regmap_write(fsl_dev->regmap, DCU_CTRLDESCLN_2(index),
> +		     DCU_CTRLDESCLN_2_POSY(state->crtc_y) |
> +		     DCU_CTRLDESCLN_2_POSX(state->crtc_x));
> +	regmap_write(fsl_dev->regmap, DCU_CTRLDESCLN_3(index), gem->paddr);
> +	regmap_write(fsl_dev->regmap, DCU_CTRLDESCLN_4(index),
> +		     DCU_CTRLDESCLN_4_EN |
> +		     DCU_CTRLDESCLN_4_TRANS(alpha) |
> +		     DCU_CTRLDESCLN_4_BPP(bpp) |
> +		     DCU_CTRLDESCLN_4_AB(0));
> +	regmap_write(fsl_dev->regmap, DCU_CTRLDESCLN_5(index),
> +		     DCU_CTRLDESCLN_5_CKMAX_R(0xFF) |
> +		     DCU_CTRLDESCLN_5_CKMAX_G(0xFF) |
> +		     DCU_CTRLDESCLN_5_CKMAX_B(0xFF));
> +	regmap_write(fsl_dev->regmap, DCU_CTRLDESCLN_6(index),
> +		     DCU_CTRLDESCLN_6_CKMIN_R(0) |
> +		     DCU_CTRLDESCLN_6_CKMIN_G(0) |
> +		     DCU_CTRLDESCLN_6_CKMIN_B(0));
> +	regmap_write(fsl_dev->regmap, DCU_CTRLDESCLN_7(index), 0);
> +	regmap_write(fsl_dev->regmap, DCU_CTRLDESCLN_8(index),
> +		     DCU_CTRLDESCLN_8_FG_FCOLOR(0));
> +	regmap_write(fsl_dev->regmap, DCU_CTRLDESCLN_9(index),
> +		     DCU_CTRLDESCLN_9_BG_BCOLOR(0));
> +	if (of_device_is_compatible(fsl_dev->np, "fsl,ls1021a-dcu"))
> +		regmap_write(fsl_dev->regmap, DCU_CTRLDESCLN_10(index),
> +			     DCU_CTRLDESCLN_10_POST_SKIP(0) |
> +			     DCU_CTRLDESCLN_10_PRE_SKIP(0));
> +	regmap_update_bits(fsl_dev->regmap, DCU_DCU_MODE,
> +			   DCU_MODE_DCU_MODE_MASK,
> +			   DCU_MODE_DCU_MODE(DCU_MODE_NORMAL));
> +	regmap_write(fsl_dev->regmap, DCU_UPDATE_MODE, DCU_UPDATE_MODE_READREG);
> +}
> +
> +int fsl_dcu_drm_plane_disable(struct drm_plane *plane)
> +{
> +	return 0;
> +}
> +
> +void fsl_dcu_drm_plane_destroy(struct drm_plane *plane)
> +{
> +	fsl_dcu_drm_plane_disable(plane);
> +	drm_plane_cleanup(plane);
> +}
> +
> +static const uint32_t fsl_dcu_drm_plane_formats[] = {
> +	DRM_FORMAT_RGB565,
> +	DRM_FORMAT_RGB888,
> +	DRM_FORMAT_ARGB8888,
> +	DRM_FORMAT_ARGB4444,
> +	DRM_FORMAT_ARGB1555,
> +	DRM_FORMAT_YUV422,
> +};
> +
> +static const struct drm_plane_funcs fsl_dcu_drm_plane_funcs = {
> +	.update_plane = drm_atomic_helper_update_plane,
> +	.disable_plane = drm_atomic_helper_disable_plane,
> +	.destroy = fsl_dcu_drm_plane_destroy,
> +	.atomic_duplicate_state = drm_atomic_helper_plane_duplicate_state,
> +	.atomic_destroy_state = drm_atomic_helper_plane_destroy_state,
> +	.reset = drm_atomic_helper_plane_reset,
> +};
> +
> +static const struct drm_plane_helper_funcs fsl_dcu_drm_plane_helper_funcs = {
> +	.prepare_fb = fsl_dcu_drm_plane_prepare_fb,
> +	.cleanup_fb = fsl_dcu_drm_plane_cleanup_fb,
> +	.atomic_check = fsl_dcu_drm_plane_atomic_check,
> +	.atomic_update = fsl_dcu_drm_plane_atomic_update,
> +	.atomic_disable = fsl_dcu_drm_plane_atomic_disable,
> +};
> +
> +struct drm_plane *fsl_dcu_drm_primary_create_plane(struct drm_device *dev)
> +{
> +	struct drm_plane *primary;
> +	int ret;
> +
> +	primary = kzalloc(sizeof(*primary), GFP_KERNEL);
> +	if (!primary) {
> +		DRM_DEBUG_KMS("Failed to allocate primary plane\n");
> +		return NULL;
> +	}
> +
> +	/* possible_crtc's will be filled in later by crtc_init */
> +	ret = drm_universal_plane_init(dev, primary, 0,
> +				       &fsl_dcu_drm_plane_funcs,
> +				       fsl_dcu_drm_plane_formats,
> +				       ARRAY_SIZE(fsl_dcu_drm_plane_formats),
> +				       DRM_PLANE_TYPE_PRIMARY);
> +	if (ret) {
> +		kfree(primary);
> +		primary = NULL;
> +	}
> +	drm_plane_helper_add(primary, &fsl_dcu_drm_plane_helper_funcs);
> +
> +	return primary;
> +}
> diff --git a/drivers/gpu/drm/fsl/fsl_dcu_drm_plane.h
> b/drivers/gpu/drm/fsl/fsl_dcu_drm_plane.h
> new file mode 100644
> index 0000000..ccbfa61
> --- /dev/null
> +++ b/drivers/gpu/drm/fsl/fsl_dcu_drm_plane.h
> @@ -0,0 +1,23 @@
> +/*
> + * Copyright 2015 Freescale Semiconductor, Inc.
> + *
> + * Freescale DCU drm device driver
> + *
> + * 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 __FSL_DCU_DRM_PLANE_H__
> +#define __FSL_DCU_DRM_PLANE_H__
> +
> +struct fsl_dcu_drm_device;
> +struct fsl_dcu_drm_plane {
> +	struct drm_plane plane;
> +	unsigned int index;
> +};
> +
> +struct drm_plane *fsl_dcu_drm_primary_create_plane(struct drm_device *dev);
> +
> +#endif /* __FSL_DCU_DRM_PLANE_H__ */
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Jianwei.Wang@freescale.com April 7, 2015, 6:44 a.m. UTC | #2
Hi Stefan,

Thank you for your review and testing on Vybrid F610 device. This driver 
just implement the basic functions and it only support the exported 
framebuffer access. Some DRM interfaces are not implemented now. So your 
test result is normal. I will implement these interfaces with patches soon 
afterwards. I don't plan to add new features for the initial version driver,
otherwise it will be a long term for this version.

I tested on ls1021a using TFT panel, there are no flickers on the screen
when inserting a USB HID device. I will do more test if time permits.

By the way, could please give me some guidance on how X-Server use DRM 
Interface directly? Do you have some papers or webpage about this?

My reply below...

> 

> Hi Jianwei,

> 

> The driver worked on a Vybrid VF610 device using the exported

> framebuffer. However, when using X-Server through the DRM interface

> directly (by using the modesetting driver) I get just a black screen so

> far, still investigating the reason. What user-space interfaces did you

> test?

> 

> When using the FB device and insert a USB HID device, I get some

> flickers on the screen. I didn't had those on the dcufb driver, did you

> notice something like this too? Probably related to the resolution, I'm

> using VGA resolution.

> 

> Some comments below.

> 

> 

> On 2015-03-26 06:37, Jianwei Wang wrote:

> > This patch add support for Two Dimensional Animation and Compositing

> > Engine (2D-ACE) on the Freescale SoCs.

> >

> > 2D-ACE is a Freescale display controller. 2D-ACE describes

> > the functionality of the module extremely well its name is a value

> > that cannot be used as a token in programming languages.

> > Instead the valid token "DCU" is used to tag the register names and

> > function names.

> >

> > The Display Controller Unit (DCU) module is a system master that

> > fetches graphics stored in internal or external memory and displays

> > them on a TFT LCD panel. A wide range of panel sizes is supported

> > and the timing of the interface signals is highly configurable.

> > Graphics are read directly from memory and then blended in real-time,

> > which allows for dynamic content creation with minimal CPU

> > intervention.

> >

> > The features:

> > (1) Full RGB888 output to TFT LCD panel.

> > (2) For the current LCD panel, WQVGA "480x272" is supported.

> > (3) Blending of each pixel using up to 4 source layers

> > dependent on size of panel.

> 

> modetest only shows one layer currently...


Yes, only one plane and one framebuffer were created now, others
maybe create as user requirement or create all when initializing,
I'm not sure now. This describe the hardware feature

> 

> > (4) Each graphic layer can be placed with one pixel resolution

> > in either axis.

> > (5) Each graphic layer support RGB565 and RGB888 direct colors

> > without alpha channel

> > and BGRA8888 direct colors with an alpha channel.

> 

> The array fsl_dcu_drm_plane_formats below shows more formats, does this

> commit log needs updating?

> 


I agree with your suggestion, I will update this commit log

> > (6) Each graphic layer support alpha blending with 8-bit

> > resolution.

> >

> > This is a simplified version, only one primary plane, one

> > framebuffer created for fbdev, one crtc, one connector for

> > TFT LCD panel, an encoder.

> >

> > Signed-off-by: Alison Wang <b18965@freescale.com>

> > Signed-off-by: Xiubo Li <lixiubo@cmss.chinamobile.com>

> > Signed-off-by: Jianwei Wang <b52261@freescale.com>

> > ---

> >

> > Changed in V3:

> >

> > - Test driver on Vybrid board and add compatible string

> > - Remove unused functions

> > - set default crtc for encoder

> > - replace legacy functions with atomic help functions

> > - Set the unique name of the DRM device

> > - Implement irq handle function for vblank interrupt

> >

> > Changed in v2:

> > - Add atomic support

> > - Modify bindings file

> > - Rename node for compatibility

> > - Move platform related code out for compatibility

> >

> >  .../devicetree/bindings/drm/fsl/fsl,dcu.txt        |  50 ++++

> >  drivers/gpu/drm/Kconfig                            |   2 +

> >  drivers/gpu/drm/Makefile                           |   1 +

> >  drivers/gpu/drm/fsl/Kconfig                        |  17 ++

> >  drivers/gpu/drm/fsl/Makefile                       |   8 +

> >  drivers/gpu/drm/fsl/fsl_dcu_drm_connector.c        | 193 ++++++++++++

> >  drivers/gpu/drm/fsl/fsl_dcu_drm_connector.h        |  30 ++

> >  drivers/gpu/drm/fsl/fsl_dcu_drm_crtc.c             | 165 ++++++++++

> >  drivers/gpu/drm/fsl/fsl_dcu_drm_crtc.h             |  26 ++

> >  drivers/gpu/drm/fsl/fsl_dcu_drm_drv.c              | 331

> +++++++++++++++++++++

> >  drivers/gpu/drm/fsl/fsl_dcu_drm_drv.h              | 210 +++++++++++++

> >  drivers/gpu/drm/fsl/fsl_dcu_drm_fbdev.c            |  26 ++

> >  drivers/gpu/drm/fsl/fsl_dcu_drm_kms.c              |  42 +++

> >  drivers/gpu/drm/fsl/fsl_dcu_drm_kms.h              |  17 ++

> >  drivers/gpu/drm/fsl/fsl_dcu_drm_plane.c            | 192 ++++++++++++

> >  drivers/gpu/drm/fsl/fsl_dcu_drm_plane.h            |  23 ++

> >  16 files changed, 1333 insertions(+)

> >  create mode 100644

> Documentation/devicetree/bindings/drm/fsl/fsl,dcu.txt

> >  create mode 100644 drivers/gpu/drm/fsl/Kconfig

> >  create mode 100644 drivers/gpu/drm/fsl/Makefile

> >  create mode 100644 drivers/gpu/drm/fsl/fsl_dcu_drm_connector.c

> >  create mode 100644 drivers/gpu/drm/fsl/fsl_dcu_drm_connector.h

> >  create mode 100644 drivers/gpu/drm/fsl/fsl_dcu_drm_crtc.c

> >  create mode 100644 drivers/gpu/drm/fsl/fsl_dcu_drm_crtc.h

> >  create mode 100644 drivers/gpu/drm/fsl/fsl_dcu_drm_drv.c

> >  create mode 100644 drivers/gpu/drm/fsl/fsl_dcu_drm_drv.h

> >  create mode 100644 drivers/gpu/drm/fsl/fsl_dcu_drm_fbdev.c

> >  create mode 100644 drivers/gpu/drm/fsl/fsl_dcu_drm_kms.c

> >  create mode 100644 drivers/gpu/drm/fsl/fsl_dcu_drm_kms.h

> >  create mode 100644 drivers/gpu/drm/fsl/fsl_dcu_drm_plane.c

> >  create mode 100644 drivers/gpu/drm/fsl/fsl_dcu_drm_plane.h

> >

> > diff --git a/Documentation/devicetree/bindings/drm/fsl/fsl,dcu.txt

> > b/Documentation/devicetree/bindings/drm/fsl/fsl,dcu.txt

> > new file mode 100644

> > index 0000000..bdc7d5b

> > --- /dev/null

> > +++ b/Documentation/devicetree/bindings/drm/fsl/fsl,dcu.txt

> > @@ -0,0 +1,50 @@

> > +Device Tree bindings for Freescale DCU DRM Driver

> > +

> > +Required properties:

> > +- compatible:           Should be one of

> > +	* "fsl,ls1021a-dcu".

> > +	* "fsl,vf610-dcu".

> 

> In the Vybrid reference manual, that IP is denoted as "DCU4". Any reason

> why you left out the DCU version? Is this different for LS1021a? On the

> other hand, with the SoC in the name, the IP should be specified clear

> enough.

> 


In the LS1021A reference manual, no DCU version related words. I asked
previous DCU owner, she told me that LS1021A use DCU5 and she also point
out that the same DCU version there may be differences between different 
SoCs. So I named compatible string with SoC name.

> > +- reg:                  Address and length of the register set for dcu.

> > +- clocks:               From common clock binding: handle to dcu clock.

> > +- clock-names:          From common clock binding: Shall be "dcu".

> > +- display:              The phandle to display node.

> > +

> > +Required properties:

> > +- bits-per-pixel:       <16> for RGB565,

> > +			<24> for RGB888,

> > +			<32> for RGB8888.

> > +

> > +Required timing node for dispplay sub-node:

> > +- display-timings:      Refer to binding doc display-timing.txt for

> details.

> > +

> > +Examples:

> > +dcu: dcu@2ce0000 {

> > +	compatible = "fsl,ls1021a-dcu";

> > +	reg = <0x0 0x2ce0000 0x0 0x10000>;

> > +	clocks = <&platform_clk 0>;

> > +	clock-names = "dcu";

> > +	big-endian;

> > +	display = <&display>;

> > +

> > +	display: display@0 {

> > +		bits-per-pixel = <24>;

> > +

> > +		display-timings {

> > +			native-mode = <&timing0>;

> > +			timing0: nl4827hc19 {

> > +				clock-frequency = <10870000>;

> > +				hactive = <480>;

> > +				vactive = <272>;

> > +				hback-porch = <2>;

> > +				hfront-porch = <2>;

> > +				vback-porch = <1>;

> > +				vfront-porch = <1>;

> > +				hsync-len = <41>;

> > +				vsync-len = <2>;

> > +				hsync-active = <1>;

> > +				vsync-active = <1>;

> > +			};

> > +		};

> > +	};

> > +};

> > +

> > diff --git a/drivers/gpu/drm/Kconfig b/drivers/gpu/drm/Kconfig

> > index 151a050..a6957aa 100644

> > --- a/drivers/gpu/drm/Kconfig

> > +++ b/drivers/gpu/drm/Kconfig

> > @@ -199,6 +199,8 @@ source "drivers/gpu/drm/bochs/Kconfig"

> >

> >  source "drivers/gpu/drm/msm/Kconfig"

> >

> > +source "drivers/gpu/drm/fsl/Kconfig"

> > +

> >  source "drivers/gpu/drm/tegra/Kconfig"

> >

> >  source "drivers/gpu/drm/panel/Kconfig"

> > diff --git a/drivers/gpu/drm/Makefile b/drivers/gpu/drm/Makefile

> > index 2c239b9..ab5b9ef 100644

> > --- a/drivers/gpu/drm/Makefile

> > +++ b/drivers/gpu/drm/Makefile

> > @@ -56,6 +56,7 @@ obj-$(CONFIG_DRM_UDL) += udl/

> >  obj-$(CONFIG_DRM_AST) += ast/

> >  obj-$(CONFIG_DRM_ARMADA) += armada/

> >  obj-$(CONFIG_DRM_ATMEL_HLCDC)	+= atmel-hlcdc/

> > +obj-$(CONFIG_DRM_FSL_DCU) += fsl/

> 

> Hm, I'm wondering whether it would be a good idea to store that driver

> under fsl-dcu/... Any opinion?

> 


I think it is good advice, I'll think about this

> >  obj-$(CONFIG_DRM_RCAR_DU) += rcar-du/

> >  obj-$(CONFIG_DRM_SHMOBILE) +=shmobile/

> >  obj-$(CONFIG_DRM_OMAP)	+= omapdrm/

> > diff --git a/drivers/gpu/drm/fsl/Kconfig b/drivers/gpu/drm/fsl/Kconfig

> > new file mode 100644

> > index 0000000..e4f8df0

> > --- /dev/null

> > +++ b/drivers/gpu/drm/fsl/Kconfig

> > @@ -0,0 +1,17 @@

> > +config DRM_FSL_DCU

> > +	tristate "DRM Support for Freescale DCU"

> > +	depends on DRM && OF && ARM

> > +	select DRM_KMS_HELPER

> > +	select DRM_KMS_CMA_HELPER

> > +	select VIDEOMODE_HELPERS

> > +	select BACKLIGHT_CLASS_DEVICE

> > +	select BACKLIGHT_LCD_SUPPORT

> > +	select REGMAP_MMIO

> > +	select DRM_KMS_FB_HELPER

> > +	select FB_SYS_FILLRECT

> > +	select FB_SYS_COPYAREA

> > +	select FB_SYS_IMAGEBLIT

> > +	select FB_SYS_FOPS

> > +	help

> > +	  Choose this option if you have an Freescale DCU chipset.

> > +	  If M is selected the module will be called fsl-dcu-drm.

> > diff --git a/drivers/gpu/drm/fsl/Makefile b/drivers/gpu/drm/fsl/Makefile

> > new file mode 100644

> > index 0000000..5f74aee

> > --- /dev/null

> > +++ b/drivers/gpu/drm/fsl/Makefile

> > @@ -0,0 +1,8 @@

> > +fsl-dcu-drm-y := fsl_dcu_drm_drv.o \

> > +	       fsl_dcu_drm_kms.o \

> > +	       fsl_dcu_drm_connector.o \

> > +	       fsl_dcu_drm_plane.o \

> > +	       fsl_dcu_drm_crtc.o \

> > +	       fsl_dcu_drm_fbdev.o \

> > +

> > +obj-$(CONFIG_DRM_FSL_DCU)	+= fsl-dcu-drm.o

> > diff --git a/drivers/gpu/drm/fsl/fsl_dcu_drm_connector.c

> > b/drivers/gpu/drm/fsl/fsl_dcu_drm_connector.c

> > new file mode 100644

> > index 0000000..4610647

> > --- /dev/null

> > +++ b/drivers/gpu/drm/fsl/fsl_dcu_drm_connector.c

> > @@ -0,0 +1,193 @@

> > +/*

> > + * Copyright 2015 Freescale Semiconductor, Inc.

> > + *

> > + * Freescale DCU drm device driver

> > + *

> > + * This program is free software; you can redistribute it and/or modify

> > + * it under the terms of the GNU General Public License as published by

> > + * the Free Software Foundation; either version 2 of the License, or

> > + * (at your option) any later version.

> > + */

> > +

> > +#include <linux/backlight.h>

> > +

> > +#include <drm/drmP.h>

> > +#include <drm/drm_atomic_helper.h>

> > +#include <video/of_display_timing.h>

> > +

> > +#include "fsl_dcu_drm_drv.h"

> > +#include "fsl_dcu_drm_connector.h"

> > +

> > +static void fsl_dcu_drm_encoder_dpms(struct drm_encoder *encoder, int

> mode)

> > +{

> > +}

> > +

> > +static void fsl_dcu_drm_encoder_mode_prepare(struct drm_encoder

> *encoder)

> > +{

> > +}

> > +

> > +static void fsl_dcu_drm_encoder_mode_set(struct drm_encoder *encoder,

> > +					 struct drm_display_mode *mode,

> > +					 struct drm_display_mode *adjusted_mode)

> > +{

> > +}

> > +

> > +static void fsl_dcu_drm_encoder_mode_commit(struct drm_encoder *encoder)

> > +{

> > +}

> > +

> > +static void fsl_dcu_drm_encoder_disable(struct drm_encoder *encoder)

> > +{

> > +}

> > +

> > +static int

> > +fsl_dcu_drm_encoder_atomic_check(struct drm_encoder *encoder,

> > +				 struct drm_crtc_state *crtc_state,

> > +				 struct drm_connector_state *conn_state)

> > +{

> > +	return 0;

> > +}

> > +

> > +static void fsl_dcu_drm_encoder_destroy(struct drm_encoder *encoder)

> > +{

> > +	drm_encoder_cleanup(encoder);

> > +}

> > +

> > +static const struct drm_encoder_helper_funcs encoder_helper_funcs = {

> > +	.dpms = fsl_dcu_drm_encoder_dpms,

> > +	.prepare = fsl_dcu_drm_encoder_mode_prepare,

> > +	.commit = fsl_dcu_drm_encoder_mode_commit,

> > +	.mode_set = fsl_dcu_drm_encoder_mode_set,

> > +	.disable = fsl_dcu_drm_encoder_disable,

> > +	.atomic_check = fsl_dcu_drm_encoder_atomic_check,

> > +};

> > +

> > +static const struct drm_encoder_funcs encoder_funcs = {

> > +	.destroy = fsl_dcu_drm_encoder_destroy,

> > +};

> > +

> > +int fsl_dcu_drm_encoder_create(struct fsl_dcu_drm_device *fsl_dev,

> > +			       struct fsl_dcu_drm_crtc *crtc)

> > +{

> > +	struct drm_encoder *encoder = &fsl_dev->encoder;

> > +	int ret;

> > +

> > +	ret = drm_encoder_init(fsl_dev->ddev, encoder, &encoder_funcs,

> > +			       DRM_MODE_ENCODER_LVDS);

> > +	if (ret < 0)

> > +		return ret;

> > +

> > +	drm_encoder_helper_add(encoder, &encoder_helper_funcs);

> > +	encoder->crtc = &crtc->crtc;

> > +

> > +	return 0;

> > +}

> > +

> > +#define to_fsl_dcu_connector(connector) \

> > +	container_of(connector, struct fsl_dcu_drm_connector, connector)

> > +

> > +static int fsl_dcu_drm_connector_get_modes(struct drm_connector

> *connector)

> > +{

> > +	struct drm_device *dev = connector->dev;

> > +	struct device_node *display_np, *np = dev->dev->of_node;

> > +	struct drm_display_mode *mode = drm_mode_create(connector->dev);

> > +	int num_modes = 0;

> > +

> > +	if (np) {

> > +		display_np = of_parse_phandle(np, "display", 0);

> > +		if (!display_np) {

> > +			dev_err(dev->dev, "failed to find display phandle\n");

> > +			return num_modes;

> > +		}

> > +		of_get_drm_display_mode(display_np, mode, OF_USE_NATIVE_MODE);

> > +		mode->type |= DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED,

> > +		drm_mode_probed_add(connector, mode);

> > +		num_modes++;

> > +	}

> > +

> > +	return num_modes;

> > +}

> > +

> > +static int fsl_dcu_drm_connector_mode_valid(struct drm_connector

> *connector,

> > +					    struct drm_display_mode *mode)

> > +{

> > +	return MODE_OK;

> > +}

> > +

> > +static struct drm_encoder *

> > +fsl_dcu_drm_connector_best_encoder(struct drm_connector *connector)

> > +{

> > +	struct fsl_dcu_drm_connector *fsl_con =

> to_fsl_dcu_connector(connector);

> > +

> > +	return fsl_con->encoder;

> > +}

> > +

> > +static void fsl_dcu_drm_connector_destroy(struct drm_connector

> *connector)

> > +{

> > +	drm_connector_unregister(connector);

> > +	drm_connector_cleanup(connector);

> > +}

> > +

> > +static enum drm_connector_status

> > +fsl_dcu_drm_connector_detect(struct drm_connector *connector, bool

> force)

> > +{

> > +	return connector_status_connected;

> > +}

> > +

> > +static const struct drm_connector_funcs fsl_dcu_drm_connector_funcs = {

> > +	.dpms = drm_atomic_helper_connector_dpms,

> > +	.reset = drm_atomic_helper_connector_reset,

> > +	.detect = fsl_dcu_drm_connector_detect,

> > +	.fill_modes = drm_helper_probe_single_connector_modes,

> > +	.destroy = fsl_dcu_drm_connector_destroy,

> > +	.atomic_duplicate_state =

> drm_atomic_helper_connector_duplicate_state,

> > +	.atomic_destroy_state = drm_atomic_helper_connector_destroy_state,

> > +};

> > +

> > +static const struct drm_connector_helper_funcs connector_helper_funcs =

> {

> > +	.get_modes = fsl_dcu_drm_connector_get_modes,

> > +	.mode_valid = fsl_dcu_drm_connector_mode_valid,

> > +	.best_encoder = fsl_dcu_drm_connector_best_encoder,

> > +};

> > +

> > +int fsl_dcu_drm_connector_create(struct fsl_dcu_drm_device *fsl_dev,

> > +				 struct drm_encoder *encoder)

> > +{

> > +	struct drm_connector *connector = &fsl_dev->connector.connector;

> > +	int ret;

> > +

> > +	fsl_dev->connector.encoder = encoder;

> > +

> > +	connector->display_info.width_mm = 0;

> > +	connector->display_info.height_mm = 0;

> > +

> > +	ret = drm_connector_init(fsl_dev->ddev, connector,

> > +				 &fsl_dcu_drm_connector_funcs,

> > +				 DRM_MODE_CONNECTOR_LVDS);

> > +	if (ret < 0)

> > +		return ret;

> > +

> > +	connector->dpms = DRM_MODE_DPMS_OFF;

> > +	drm_connector_helper_add(connector, &connector_helper_funcs);

> > +	ret = drm_connector_register(connector);

> > +	if (ret < 0)

> > +		goto err_cleanup;

> > +

> > +	ret = drm_mode_connector_attach_encoder(connector, encoder);

> > +	if (ret < 0)

> > +		goto err_sysfs;

> > +

> > +	connector->encoder = encoder;

> > +

> > +	drm_object_property_set_value

> > +		(&connector->base, fsl_dev->ddev->mode_config.dpms_property,

> > +		DRM_MODE_DPMS_OFF);

> > +

> > +	return 0;

> > +

> > +err_sysfs:

> > +	drm_connector_unregister(connector);

> > +err_cleanup:

> > +	drm_connector_cleanup(connector);

> > +	return ret;

> > +}

> > diff --git a/drivers/gpu/drm/fsl/fsl_dcu_drm_connector.h

> > b/drivers/gpu/drm/fsl/fsl_dcu_drm_connector.h

> > new file mode 100644

> > index 0000000..bbf6d38

> > --- /dev/null

> > +++ b/drivers/gpu/drm/fsl/fsl_dcu_drm_connector.h

> > @@ -0,0 +1,30 @@

> > +/*

> > + * Copyright 2015 Freescale Semiconductor, Inc.

> > + *

> > + * Freescale DCU drm device driver

> > + *

> > + * 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 __FSL_DCU_DRM_CONNECTOR_H__

> > +#define __FSL_DCU_DRM_CONNECTOR_H__

> > +

> > +#include <drm/drmP.h>

> > +#include <drm/drm_crtc.h>

> > +#include "fsl_dcu_drm_crtc.h"

> > +

> > +struct fsl_dcu_drm_device;

> > +struct fsl_dcu_drm_connector {

> > +	struct drm_connector connector;

> > +	struct drm_encoder *encoder;

> > +};

> > +

> > +int fsl_dcu_drm_encoder_create(struct fsl_dcu_drm_device *fsl_dev,

> > +			       struct fsl_dcu_drm_crtc *crtc);

> > +int fsl_dcu_drm_connector_create(struct fsl_dcu_drm_device *fsl_dev,

> > +				 struct drm_encoder *encoder);

> > +

> > +#endif /* __FSL_DCU_DRM_CONNECTOR_H__ */

> > diff --git a/drivers/gpu/drm/fsl/fsl_dcu_drm_crtc.c

> > b/drivers/gpu/drm/fsl/fsl_dcu_drm_crtc.c

> > new file mode 100644

> > index 0000000..076e273

> > --- /dev/null

> > +++ b/drivers/gpu/drm/fsl/fsl_dcu_drm_crtc.c

> > @@ -0,0 +1,165 @@

> > +/*

> > + * Copyright 2015 Freescale Semiconductor, Inc.

> > + *

> > + * Freescale DCU drm device driver

> > + *

> > + * This program is free software; you can redistribute it and/or modify

> > + * it under the terms of the GNU General Public License as published by

> > + * the Free Software Foundation; either version 2 of the License, or

> > + * (at your option) any later version.

> > + */

> > +

> > +#include <linux/regmap.h>

> > +#include <linux/clk.h>

> > +

> > +#include <drm/drmP.h>

> > +#include <drm/drm_atomic.h>

> > +#include <drm/drm_atomic_helper.h>

> > +#include <drm/drm_crtc.h>

> > +

> > +#include "fsl_dcu_drm_crtc.h"

> > +#include "fsl_dcu_drm_drv.h"

> > +#include "fsl_dcu_drm_plane.h"

> > +

> > +#define to_fsl_dcu_crtc(c)	container_of(c, struct fsl_dcu_drm_crtc,

> crtc)

> > +

> > +void fsl_dcu_drm_crtc_suspend(struct drm_crtc *crtc)

> > +{

> > +}

> > +

> > +static void fsl_dcu_drm_crtc_mode_set_nofb(struct drm_crtc *crtc)

> > +{

> > +	struct drm_device *dev = crtc->dev;

> > +	struct fsl_dcu_drm_device *fsl_dev = dev->dev_private;

> > +	struct drm_display_mode *mode = &crtc->state->mode;

> > +	uint32_t hbp, hfp, hsw, vbp, vfp, vsw, div, index;

> > +

> > +	DBG(": set mode: %d:\"%s\" %d %d %d %d %d %d %d %d %d %d 0x%x 0x%x",

> > +	    mode->base.id, mode->name,

> > +	    mode->vrefresh, mode->clock,

> > +	    mode->hdisplay, mode->hsync_start,

> > +	    mode->hsync_end, mode->htotal,

> > +	    mode->vdisplay, mode->vsync_start,

> > +	    mode->vsync_end, mode->vtotal,

> > +	    mode->type, mode->flags);

> > +

> > +	index = drm_crtc_index(crtc);

> > +	div = (uint32_t)clk_get_rate(fsl_dev->clk) / mode->clock / 1000;

> > +

> > +	/* Configure timings: */

> > +	hbp = mode->htotal - mode->hsync_end;

> > +	hfp = mode->hsync_start - mode->hdisplay;

> > +	hsw = mode->hsync_end - mode->hsync_start;

> > +	vbp = mode->vtotal - mode->vsync_end;

> > +	vfp = mode->vsync_start - mode->vdisplay;

> > +	vsw = mode->vsync_end - mode->vsync_start;

> > +

> > +	regmap_write(fsl_dev->regmap, DCU_HSYN_PARA,

> > +		     DCU_HSYN_PARA_BP(hbp) |

> > +		     DCU_HSYN_PARA_PW(hsw) |

> > +		     DCU_HSYN_PARA_FP(hfp));

> > +	regmap_write(fsl_dev->regmap, DCU_VSYN_PARA,

> > +		     DCU_VSYN_PARA_BP(vbp) |

> > +		     DCU_VSYN_PARA_PW(vsw) |

> > +		     DCU_VSYN_PARA_FP(vfp));

> > +	regmap_write(fsl_dev->regmap, DCU_DISP_SIZE,

> > +		     DCU_DISP_SIZE_DELTA_Y(mode->vdisplay) |

> > +		     DCU_DISP_SIZE_DELTA_X(mode->hdisplay));

> > +	regmap_write(fsl_dev->regmap, DCU_DIV_RATIO, div);

> > +	regmap_write(fsl_dev->regmap, DCU_UPDATE_MODE,

> DCU_UPDATE_MODE_READREG);

> > +}

> > +

> > +static bool fsl_dcu_drm_crtc_mode_fixup(struct drm_crtc *crtc,

> > +					const struct drm_display_mode *mode,

> > +					struct drm_display_mode *adjusted_mode)

> > +{

> > +	return true;

> > +}

> > +

> > +static void fsl_dcu_drm_crtc_prepare(struct drm_crtc *crtc)

> > +{

> > +}

> > +

> > +/* Now enable the clocks, plane, pipe, and connectors that we set up.

> */

> > +static void fsl_dcu_drm_crtc_mode_commit(struct drm_crtc *crtc)

> > +{

> > +}

> > +

> > +static int fsl_dcu_drm_crtc_atomic_check(struct drm_crtc *crtc,

> > +					 struct drm_crtc_state *state)

> > +{

> > +	return 0;

> > +}

> > +

> > +static void fsl_dcu_drm_crtc_atomic_begin(struct drm_crtc *crtc)

> > +{

> > +}

> > +

> > +static void fsl_dcu_drm_crtc_atomic_flush(struct drm_crtc *crtc)

> > +{

> > +}

> > +

> > +static void fsl_dcu_drm_disable_crtc(struct drm_crtc *crtc)

> > +{

> > +}

> > +

> > +static const struct drm_crtc_funcs fsl_dcu_drm_crtc_funcs = {

> > +	.page_flip = drm_atomic_helper_page_flip,

> > +	.set_config = drm_atomic_helper_set_config,

> > +	.destroy = drm_crtc_cleanup,

> > +	.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 void fsl_dcu_drm_crtc_dpms(struct drm_crtc *crtc, int mode)

> > +{

> > +}

> > +

> > +static const struct drm_crtc_helper_funcs fsl_dcu_drm_crtc_helper_funcs

> = {

> > +	.disable = fsl_dcu_drm_disable_crtc,

> > +	.mode_fixup = fsl_dcu_drm_crtc_mode_fixup,

> > +	.mode_set = drm_helper_crtc_mode_set,

> > +	.mode_set_nofb = fsl_dcu_drm_crtc_mode_set_nofb,

> > +	.mode_set_base = drm_helper_crtc_mode_set_base,

> > +	.prepare = fsl_dcu_drm_crtc_prepare,

> > +	.commit = fsl_dcu_drm_crtc_mode_commit,

> > +	.atomic_check = fsl_dcu_drm_crtc_atomic_check,

> > +	.atomic_begin = fsl_dcu_drm_crtc_atomic_begin,

> > +	.atomic_flush = fsl_dcu_drm_crtc_atomic_flush,

> > +	.dpms = fsl_dcu_drm_crtc_dpms,

> > +};

> > +

> > +int fsl_dcu_drm_crtc_create(struct fsl_dcu_drm_device *fsl_dev)

> > +{

> > +	struct drm_plane *primary;

> > +	struct drm_crtc *crtc = &fsl_dev->crtc.crtc;

> > +	int ret;

> > +

> > +	fsl_dev->crtc.dpms = DRM_MODE_DPMS_OFF;

> > +

> > +	primary = fsl_dcu_drm_primary_create_plane(fsl_dev->ddev);

> > +	ret = drm_crtc_init_with_planes(fsl_dev->ddev, crtc, primary, NULL,

> > +					&fsl_dcu_drm_crtc_funcs);

> > +	if (ret < 0)

> > +		return ret;

> > +

> > +	drm_crtc_helper_add(crtc, &fsl_dcu_drm_crtc_helper_funcs);

> > +

> > +	regmap_write(fsl_dev->regmap, DCU_SYN_POL,

> > +		     DCU_SYN_POL_INV_VS_LOW | DCU_SYN_POL_INV_HS_LOW);

> > +	regmap_write(fsl_dev->regmap, DCU_BGND, DCU_BGND_R(0) |

> > +		     DCU_BGND_G(0) | DCU_BGND_B(0));

> > +	regmap_write(fsl_dev->regmap, DCU_DCU_MODE,

> > +		     DCU_MODE_BLEND_ITER(1) | DCU_MODE_RASTER_EN);

> > +	regmap_write(fsl_dev->regmap, DCU_THRESHOLD,

> > +		     DCU_THRESHOLD_LS_BF_VS(BF_VS_VAL) |

> > +		     DCU_THRESHOLD_OUT_BUF_HIGH(BUF_MAX_VAL) |

> > +		     DCU_THRESHOLD_OUT_BUF_LOW(BUF_MIN_VAL));

> > +	regmap_update_bits(fsl_dev->regmap, DCU_DCU_MODE,

> > +			   DCU_MODE_DCU_MODE_MASK,

> > +			   DCU_MODE_DCU_MODE(DCU_MODE_OFF));

> > +	regmap_write(fsl_dev->regmap, DCU_UPDATE_MODE,

> DCU_UPDATE_MODE_READREG);

> > +

> > +	return 0;

> > +}

> > diff --git a/drivers/gpu/drm/fsl/fsl_dcu_drm_crtc.h

> > b/drivers/gpu/drm/fsl/fsl_dcu_drm_crtc.h

> > new file mode 100644

> > index 0000000..d44b564

> > --- /dev/null

> > +++ b/drivers/gpu/drm/fsl/fsl_dcu_drm_crtc.h

> > @@ -0,0 +1,26 @@

> > +/*

> > + * Copyright 2015 Freescale Semiconductor, Inc.

> > + *

> > + * Freescale DCU drm device driver

> > + *

> > + * 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 __FSL_DCU_DRM_CRTC_H__

> > +#define __FSL_DCU_DRM_CRTC_H__

> > +

> > +#include <drm/drmP.h>

> > +#include <drm/drm_crtc.h>

> > +

> > +struct fsl_dcu_drm_device;

> > +struct fsl_dcu_drm_crtc {

> > +	struct drm_crtc crtc;

> > +	int dpms;

> > +};

> > +

> > +int fsl_dcu_drm_crtc_create(struct fsl_dcu_drm_device *fsl_dev);

> > +

> > +#endif /* __FSL_DCU_DRM_CRTC_H__ */

> > diff --git a/drivers/gpu/drm/fsl/fsl_dcu_drm_drv.c

> > b/drivers/gpu/drm/fsl/fsl_dcu_drm_drv.c

> > new file mode 100644

> > index 0000000..d4a559a

> > --- /dev/null

> > +++ b/drivers/gpu/drm/fsl/fsl_dcu_drm_drv.c

> > @@ -0,0 +1,331 @@

> > +/*

> > + * Copyright 2015 Freescale Semiconductor, Inc.

> > + *

> > + * Freescale DCU drm device driver

> > + *

> > + * This program is free software; you can redistribute it and/or modify

> > + * it under the terms of the GNU General Public License as published by

> > + * the Free Software Foundation; either version 2 of the License, or

> > + * (at your option) any later version.

> > + */

> > +

> > +#include <linux/clk.h>

> > +#include <linux/io.h>

> > +#include <linux/mm.h>

> > +#include <linux/module.h>

> > +#include <linux/of_platform.h>

> > +#include <linux/platform_device.h>

> > +#include <linux/pm.h>

> > +#include <linux/pm_runtime.h>

> > +#include <linux/regmap.h>

> > +

> > +#include <drm/drmP.h>

> > +#include <linux/fsl/dcu.h>

> 

> This file seems to be missing in that patch.

> 

 
This file in patch 2/4, It's LS1021A platform related code.

> > +

> > +#include "fsl_dcu_drm_drv.h"

> > +#include "fsl_dcu_drm_kms.h"

> > +

> > +static int fsl_dcu_unload(struct drm_device *dev)

> > +{

> > +	drm_mode_config_cleanup(dev);

> > +	drm_vblank_cleanup(dev);

> > +	drm_irq_uninstall(dev);

> > +

> > +	dev->dev_private = NULL;

> > +

> > +	return 0;

> > +}

> > +

> > +static struct regmap_config fsl_dcu_regmap_config = {

> > +	.reg_bits = 32,

> > +	.reg_stride = 4,

> > +	.val_bits = 32,

> > +};

> > +

> > +static int fsl_dcu_bypass_tcon(struct fsl_dcu_drm_device *fsl_dev,

> > +			       struct device_node *np)

> > +{

> > +	struct device_node *tcon_np;

> > +	struct platform_device *pdev;

> > +	struct clk *tcon_clk;

> > +	struct resource *res;

> > +	void __iomem *base;

> > +

> > +	tcon_np = of_parse_phandle(np, "tcon-controller", 0);

> > +	if (!tcon_np)

> > +		return -EINVAL;

> > +

> > +	pdev = of_find_device_by_node(tcon_np);

> > +	if (!pdev)

> > +		return -EINVAL;

> > +

> > +	tcon_clk = devm_clk_get(&pdev->dev, "tcon");

> > +	if (IS_ERR(tcon_clk))

> > +		return PTR_ERR(tcon_clk);

> > +	clk_prepare_enable(tcon_clk);

> 

> You enable the clock explicitly...

> 

> > +

> > +	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);

> > +	if (!res)

> > +		return -ENODEV;

> > +

> > +	base = devm_ioremap_resource(&pdev->dev, res);

> > +	if (IS_ERR(base))

> > +		return PTR_ERR(base);

> > +

> > +	fsl_dev->tcon_regmap = devm_regmap_init_mmio_clk(&pdev->dev,

> > +			"tcon", base, &fsl_dcu_regmap_config);

> 

> And implicitly using regmap. In a short test on Vybrid, the clock is

> actually not needed during operation, hence we could use the explicit

> enabling above, what do you think?

> 

> Also, the clock and tcon in general currently does not get handled by

> suspend/resume code...

> 


OK, I'll update code here

> > +	if (IS_ERR(fsl_dev->tcon_regmap)) {

> > +		dev_err(&pdev->dev, "regmap init failed\n");

> > +		return PTR_ERR(fsl_dev->tcon_regmap);

> > +	}

> > +

> > +	regmap_write(fsl_dev->tcon_regmap, TCON_CTRL1, TCON_BYPASS_ENABLE);

> > +	return 0;

> > +}

> > +

> > +static int fsl_dcu_drm_irq_init(struct drm_device *dev)

> > +{

> > +	struct platform_device *pdev = dev->platformdev;

> > +	struct fsl_dcu_drm_device *fsl_dev = dev->dev_private;

> > +	unsigned int int_mask;

> > +	int ret;

> > +

> > +	ret = drm_irq_install(dev, platform_get_irq(dev->platformdev, 0));

> > +	if (ret < 0)

> > +		dev_err(&pdev->dev, "failed to install IRQ handler\n");

> > +

> > +	dev->irq_enabled = true;

> > +	dev->vblank_disable_allowed = true;

> > +

> > +	regmap_write(fsl_dev->regmap, DCU_INT_STATUS, 0);

> > +	regmap_read(fsl_dev->regmap, DCU_INT_MASK, &int_mask);

> > +	regmap_write(fsl_dev->regmap, DCU_INT_MASK, int_mask &

> > +		     ~DCU_INT_MASK_VBLANK);

> > +	regmap_write(fsl_dev->regmap, DCU_UPDATE_MODE,

> DCU_UPDATE_MODE_READREG);

> > +

> > +	return 0;

> > +}

> > +

> > +static int fsl_dcu_load(struct drm_device *dev, unsigned long flags)

> > +{

> > +	struct platform_device *pdev = dev->platformdev;

> > +	struct fsl_dcu_drm_device *fsl_dev;

> > +	struct resource *res;

> > +	void __iomem *base;

> > +	int ret;

> > +

> > +	fsl_dev = devm_kzalloc(&pdev->dev, sizeof(*fsl_dev), GFP_KERNEL);

> > +	if (!fsl_dev)

> > +		return -ENOMEM;

> > +

> > +	fsl_dev->dev = &pdev->dev;

> > +	fsl_dev->ddev = dev;

> > +	fsl_dev->np = pdev->dev.of_node;

> > +	dev->dev_private = fsl_dev;

> > +	drm_dev_set_unique(dev, dev_name(dev->dev));

> > +

> > +	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);

> > +	if (!res) {

> > +		dev_err(&pdev->dev, "could not get memory IO resource\n");

> > +		return -ENODEV;

> > +	}

> > +

> > +	base = devm_ioremap_resource(&pdev->dev, res);

> > +	if (IS_ERR(base)) {

> > +		ret = PTR_ERR(base);

> > +		return ret;

> > +	}

> > +

> > +	fsl_dev->regmap = devm_regmap_init_mmio_clk(&pdev->dev, NULL,

> > +			base, &fsl_dcu_regmap_config);

> > +	if (IS_ERR(fsl_dev->regmap)) {

> > +		dev_err(&pdev->dev, "regmap init failed\n");

> > +		return PTR_ERR(fsl_dev->regmap);

> > +	}

> > +

> > +	/* Put TCON in bypass mode, so the input signals from DCU are passed

> > +	 * through TCON unchanged */

> > +	fsl_dcu_bypass_tcon(fsl_dev, fsl_dev->np);

> > +	fsl_dev->clk = devm_clk_get(&pdev->dev, "dcu");

> > +	if (IS_ERR(fsl_dev->clk)) {

> > +		ret = PTR_ERR(fsl_dev->clk);

> > +		dev_err(&pdev->dev, "could not get clock\n");

> > +		return ret;

> > +	}

> > +	clk_prepare_enable(fsl_dev->clk);

> > +	dev_set_drvdata(dev->dev, fsl_dev);

> > +

> > +	ret = fsl_dcu_drm_modeset_init(fsl_dev);

> > +	if (ret < 0) {

> > +		dev_err(&pdev->dev, "failed to initialize mode setting\n");

> > +		return ret;

> > +	}

> > +

> > +	ret = drm_vblank_init(dev, dev->mode_config.num_crtc);

> > +	if (ret < 0) {

> > +		dev_err(&pdev->dev, "failed to initialize vblank\n");

> > +		goto done;

> > +	}

> > +

> > +	ret = fsl_dcu_drm_irq_init(dev);

> > +	if (ret < 0)

> > +		goto done;

> > +

> > +	fsl_dcu_fbdev_init(dev);

> > +

> > +	return 0;

> > +done:

> > +	if (ret)

> > +		fsl_dcu_unload(dev);

> > +

> > +	return ret;

> > +}

> > +

> > +static void fsl_dcu_drm_preclose(struct drm_device *dev, struct

> drm_file *file)

> > +{

> > +	;

> > +}

> > +

> > +static irqreturn_t fsl_dcu_drm_irq(int irq, void *arg)

> > +{

> > +	struct drm_device *dev = arg;

> > +	struct fsl_dcu_drm_device *fsl_dev = dev->dev_private;

> > +	unsigned int int_status;

> > +

> > +	regmap_read(fsl_dev->regmap, DCU_INT_STATUS, &int_status);

> > +	if (int_status & DCU_INT_STATUS_VBLANK)

> > +		drm_handle_vblank(dev, 0);

> > +

> > +	regmap_write(fsl_dev->regmap, DCU_INT_STATUS, 0xffffffff);

> > +	regmap_write(fsl_dev->regmap, DCU_UPDATE_MODE,

> DCU_UPDATE_MODE_READREG);

> > +

> > +	return IRQ_HANDLED;

> > +}

> > +

> > +static int fsl_dcu_drm_enable_vblank(struct drm_device *dev, int crtc)

> > +{

> > +	return 0;

> > +}

> > +

> > +static void fsl_dcu_drm_disable_vblank(struct drm_device *dev, int crtc)

> > +{

> > +	;

> > +}

> > +

> > +static const struct file_operations fsl_dcu_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		= no_llseek,

> > +	.mmap		= drm_gem_cma_mmap,

> > +};

> > +

> > +static struct drm_driver fsl_dcu_drm_driver = {

> > +	.driver_features	= DRIVER_HAVE_IRQ | DRIVER_GEM | DRIVER_MODESET

> > +				| DRIVER_PRIME,

> > +	.load			= fsl_dcu_load,

> > +	.unload			= fsl_dcu_unload,

> > +	.preclose		= fsl_dcu_drm_preclose,

> > +	.irq_handler		= fsl_dcu_drm_irq,

> > +	.get_vblank_counter	= drm_vblank_count,

> > +	.enable_vblank		= fsl_dcu_drm_enable_vblank,

> > +	.disable_vblank		= fsl_dcu_drm_disable_vblank,

> > +	.gem_free_object	= drm_gem_cma_free_object,

> > +	.gem_vm_ops		= &drm_gem_cma_vm_ops,

> > +	.prime_handle_to_fd	= drm_gem_prime_handle_to_fd,

> > +	.prime_fd_to_handle	= drm_gem_prime_fd_to_handle,

> > +	.gem_prime_import	= drm_gem_prime_import,

> > +	.gem_prime_export	= drm_gem_prime_export,

> > +	.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,

> > +	.dumb_create		= drm_gem_cma_dumb_create,

> > +	.dumb_map_offset	= drm_gem_cma_dumb_map_offset,

> > +	.dumb_destroy		= drm_gem_dumb_destroy,

> > +	.fops			= &fsl_dcu_drm_fops,

> > +	.name			= "fsl-dcu-drm",

> > +	.desc			= "Freescale DCU DRM",

> > +	.date			= "20150213",

> > +	.major			= 1,

> > +	.minor			= 0,

> > +};

> > +

> > +#ifdef CONFIG_PM_SLEEP

> > +static int fsl_dcu_drm_pm_suspend(struct device *dev)

> > +{

> > +	struct fsl_dcu_drm_device *fsl_dev = dev_get_drvdata(dev);

> > +

> > +	if (of_device_is_compatible(fsl_dev->np, "fsl,ls1021a-dcu"))

> > +		dcu_pixclk_disable();

> > +

> > +	drm_kms_helper_poll_disable(fsl_dev->ddev);

> > +	fsl_dcu_drm_crtc_suspend(&fsl_dev->crtc);

> 

> I get

> 

> drivers/gpu/drm/fsl/fsl_dcu_drm_drv.c: In function

> 'fsl_dcu_drm_pm_suspend':

> drivers/gpu/drm/fsl/fsl_dcu_drm_drv.c:270:2: error: implicit declaration

> of function 'fsl_dcu_drm_crtc_suspend'

> [-Werror=implicit-function-declaration]

>   fsl_dcu_drm_crtc_suspend(&fsl_dev->crtc);

>   ^

> drivers/gpu/drm/fsl/fsl_dcu_drm_drv.c: In function

> 'fsl_dcu_drm_pm_resume':

> drivers/gpu/drm/fsl/fsl_dcu_drm_drv.c:280:2: error: implicit declaration

> of function 'fsl_dcu_drm_crtc_resume'

> [-Werror=implicit-function-declaration]

>   fsl_dcu_drm_crtc_resume(&fsl_dev->crtc);

>   ^

> 

> The function fsl_dcu_drm_crtc_suspend seems to be part of

> fsl_dcu_drm_crtc.c, but is empty. While the other is missing

> completely... Please fix/remove as appropriate.

> 


OK, I'll fix it

Regards
Jianwei
> > +

> > +	return 0;

> > +}

> > +

> > +static int fsl_dcu_drm_pm_resume(struct device *dev)

> > +{

> > +	struct fsl_dcu_drm_device *fsl_dev = dev_get_drvdata(dev);

> > +

> > +	drm_modeset_lock_all(fsl_dev->ddev);

> > +	fsl_dcu_drm_crtc_resume(&fsl_dev->crtc);

> > +	drm_modeset_unlock_all(fsl_dev->ddev);

> > +	drm_kms_helper_poll_enable(fsl_dev->ddev);

> > +

> > +	if (of_device_is_compatible(fsl_dev->np, "fsl,ls1021a-dcu"))

> > +		dcu_pixclk_enable();

> > +

> > +	return 0;

> > +}

> > +#endif

> > +

> > +static const struct dev_pm_ops fsl_dcu_drm_pm_ops = {

> > +	SET_SYSTEM_SLEEP_PM_OPS(fsl_dcu_drm_pm_suspend,

> fsl_dcu_drm_pm_resume)

> > +};

> > +

> > +static int fsl_dcu_drm_probe(struct platform_device *pdev)

> > +{

> > +	return drm_platform_init(&fsl_dcu_drm_driver, pdev);

> > +}

> > +

> > +static int fsl_dcu_drm_remove(struct platform_device *pdev)

> > +{

> > +	struct fsl_dcu_drm_device *fsl_dev = platform_get_drvdata(pdev);

> > +

> > +	drm_put_dev(fsl_dev->ddev);

> > +

> > +	return 0;

> > +}

> > +

> > +static const struct of_device_id fsl_dcu_of_match[] = {

> > +		{ .compatible = "fsl,ls1021a-dcu", },

> > +		{ .compatible = "fsl,vf610-dcu", },

> > +		{ },

> > +};

> > +MODULE_DEVICE_TABLE(of, fsl_dcu_of_match);

> > +

> > +static struct platform_driver fsl_dcu_drm_platform_driver = {

> > +	.probe		= fsl_dcu_drm_probe,

> > +	.remove		= fsl_dcu_drm_remove,

> > +	.driver		= {

> > +		.owner	= THIS_MODULE,

> > +		.name	= "fsl,dcu",

> > +		.pm	= &fsl_dcu_drm_pm_ops,

> > +		.of_match_table = fsl_dcu_of_match,

> > +	},

> > +};

> > +

> > +module_platform_driver(fsl_dcu_drm_platform_driver);

> > +

> > +MODULE_ALIAS("platform:fsl-dcu-drm");

> > +MODULE_DESCRIPTION("Freescale DCU DRM Driver");

> > +MODULE_LICENSE("GPL");

> > diff --git a/drivers/gpu/drm/fsl/fsl_dcu_drm_drv.h

> > b/drivers/gpu/drm/fsl/fsl_dcu_drm_drv.h

> > new file mode 100644

> > index 0000000..27226109

> > --- /dev/null

> > +++ b/drivers/gpu/drm/fsl/fsl_dcu_drm_drv.h

> > @@ -0,0 +1,210 @@

> > +/*

> > + * Copyright 2015 Freescale Semiconductor, Inc.

> > + *

> > + * Freescale DCU drm device driver

> > + *

> > + * 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 __FSL_DCU_DRM_DRV_H__

> > +#define __FSL_DCU_DRM_DRV_H__

> > +

> > +#include <linux/kernel.h>

> > +#include <linux/spinlock.h>

> > +#include <stddef.h>

> > +#include <drm/drm.h>

> > +#include <drm/drmP.h>

> > +#include <drm/drm_fb_helper.h>

> > +#include <drm/drm_crtc_helper.h>

> > +#include <drm/drm_gem_cma_helper.h>

> > +#include <drm/drm_fb_cma_helper.h>

> > +

> > +#include "fsl_dcu_drm_crtc.h"

> > +#include "fsl_dcu_drm_plane.h"

> > +#include "fsl_dcu_drm_connector.h"

> > +#define DRIVER_NAME			"fsl-dcu-drm"

> > +

> > +#define DCU_DCU_MODE			0x0010

> > +#define DCU_MODE_BLEND_ITER(x)		((x) << 20)

> > +#define DCU_MODE_RASTER_EN		BIT(14)

> > +#define DCU_MODE_DCU_MODE(x)		(x)

> > +#define DCU_MODE_DCU_MODE_MASK		0x03

> > +#define DCU_MODE_OFF			0

> > +#define DCU_MODE_NORMAL			1

> > +#define DCU_MODE_TEST			2

> > +#define DCU_MODE_COLORBAR		3

> > +

> > +#define DCU_BGND			0x0014

> > +#define DCU_BGND_R(x)			((x) << 16)

> > +#define DCU_BGND_G(x)			((x) << 8)

> > +#define DCU_BGND_B(x)			(x)

> > +

> > +#define DCU_DISP_SIZE			0x0018

> > +#define DCU_DISP_SIZE_DELTA_Y(x)	((x) << 16)

> > +/*Regisiter value 1/16 of horizontal resolution*/

> > +#define DCU_DISP_SIZE_DELTA_X(x)	((x) >> 4)

> > +

> > +#define DCU_HSYN_PARA			0x001c

> > +#define DCU_HSYN_PARA_BP(x)		((x) << 22)

> > +#define DCU_HSYN_PARA_PW(x)		((x) << 11)

> > +#define DCU_HSYN_PARA_FP(x)		(x)

> > +

> > +#define DCU_VSYN_PARA			0x0020

> > +#define DCU_VSYN_PARA_BP(x)		((x) << 22)

> > +#define DCU_VSYN_PARA_PW(x)		((x) << 11)

> > +#define DCU_VSYN_PARA_FP(x)		(x)

> > +

> > +#define DCU_SYN_POL			0x0024

> > +#define DCU_SYN_POL_INV_PXCK_FALL	(0 << 6)

> > +#define DCU_SYN_POL_NEG_REMAIN		(0 << 5)

> > +#define DCU_SYN_POL_INV_VS_LOW		BIT(1)

> > +#define DCU_SYN_POL_INV_HS_LOW		BIT(0)

> > +

> > +#define DCU_THRESHOLD			0x0028

> > +#define DCU_THRESHOLD_LS_BF_VS(x)	((x) << 16)

> > +#define DCU_THRESHOLD_OUT_BUF_HIGH(x)	((x) << 8)

> > +#define DCU_THRESHOLD_OUT_BUF_LOW(x)	(x)

> > +#define BF_VS_VAL			0x03

> > +#define BUF_MAX_VAL			0x78

> > +#define BUF_MIN_VAL			0x0a

> > +

> > +#define DCU_INT_STATUS			0x002C

> > +#define DCU_INT_STATUS_VSYNC		BIT(0)

> > +#define DCU_INT_STATUS_UNDRUN		BIT(1)

> > +#define DCU_INT_STATUS_LSBFVS		BIT(2)

> > +#define DCU_INT_STATUS_VBLANK		BIT(3)

> > +#define DCU_INT_STATUS_CRCREADY		BIT(4)

> > +#define DCU_INT_STATUS_CRCOVERFLOW	BIT(5)

> > +#define DCU_INT_STATUS_P1FIFOLO		BIT(6)

> > +#define DCU_INT_STATUS_P1FIFOHI		BIT(7)

> > +#define DCU_INT_STATUS_P2FIFOLO		BIT(8)

> > +#define DCU_INT_STATUS_P2FIFOHI		BIT(9)

> > +#define DCU_INT_STATUS_PROGEND		BIT(10)

> > +#define DCU_INT_STATUS_IPMERROR		BIT(11)

> > +#define DCU_INT_STATUS_LYRTRANS		BIT(12)

> > +#define DCU_INT_STATUS_DMATRANS		BIT(14)

> > +#define DCU_INT_STATUS_P3FIFOLO		BIT(16)

> > +#define DCU_INT_STATUS_P3FIFOHI		BIT(17)

> > +#define DCU_INT_STATUS_P4FIFOLO		BIT(18)

> > +#define DCU_INT_STATUS_P4FIFOHI		BIT(19)

> > +#define DCU_INT_STATUS_P1EMPTY		BIT(26)

> > +#define DCU_INT_STATUS_P2EMPTY		BIT(27)

> > +#define DCU_INT_STATUS_P3EMPTY		BIT(28)

> > +#define DCU_INT_STATUS_P4EMPTY		BIT(29)

> > +

> > +#define DCU_INT_MASK			0x0030

> > +#define DCU_INT_MASK_VSYNC		BIT(0)

> > +#define DCU_INT_MASK_UNDRUN		BIT(1)

> > +#define DCU_INT_MASK_LSBFVS		BIT(2)

> > +#define DCU_INT_MASK_VBLANK		BIT(3)

> > +#define DCU_INT_MASK_CRCREADY		BIT(4)

> > +#define DCU_INT_MASK_CRCOVERFLOW	BIT(5)

> > +#define DCU_INT_MASK_P1FIFOLO		BIT(6)

> > +#define DCU_INT_MASK_P1FIFOHI		BIT(7)

> > +#define DCU_INT_MASK_P2FIFOLO		BIT(8)

> > +#define DCU_INT_MASK_P2FIFOHI		BIT(9)

> > +#define DCU_INT_MASK_PROGEND		BIT(10)

> > +#define DCU_INT_MASK_IPMERROR		BIT(11)

> > +#define DCU_INT_MASK_LYRTRANS		BIT(12)

> > +#define DCU_INT_MASK_DMATRANS		BIT(14)

> > +#define DCU_INT_MASK_P3FIFOLO		BIT(16)

> > +#define DCU_INT_MASK_P3FIFOHI		BIT(17)

> > +#define DCU_INT_MASK_P4FIFOLO		BIT(18)

> > +#define DCU_INT_MASK_P4FIFOHI		BIT(19)

> > +#define DCU_INT_MASK_P1EMPTY		BIT(26)

> > +#define DCU_INT_MASK_P2EMPTY		BIT(27)

> > +#define DCU_INT_MASK_P3EMPTY		BIT(28)

> > +#define DCU_INT_MASK_P4EMPTY		BIT(29)

> > +

> > +#define DCU_DIV_RATIO			0x0054

> > +

> > +#define DCU_UPDATE_MODE			0x00cc

> > +#define DCU_UPDATE_MODE_MODE		BIT(31)

> > +#define DCU_UPDATE_MODE_READREG		BIT(30)

> > +

> > +#define DCU_DCFB_MAX			0x300

> > +

> > +#define DCU_CTRLDESCLN_1(x)		(0x200 + (x) * 0x40)

> > +#define DCU_CTRLDESCLN_1_HEIGHT(x)	((x) << 16)

> > +#define DCU_CTRLDESCLN_1_WIDTH(x)	(x)

> > +

> > +#define DCU_CTRLDESCLN_2(x)		(0x204 + (x) * 0x40)

> > +#define DCU_CTRLDESCLN_2_POSY(x)	((x) << 16)

> > +#define DCU_CTRLDESCLN_2_POSX(x)	(x)

> > +

> > +#define DCU_CTRLDESCLN_3(x)		(0x208 + (x) * 0x40)

> > +

> > +#define DCU_CTRLDESCLN_4(x)		(0x20c + (x) * 0x40)

> > +#define DCU_CTRLDESCLN_4_EN		BIT(31)

> > +#define DCU_CTRLDESCLN_4_TILE_EN	BIT(30)

> > +#define DCU_CTRLDESCLN_4_DATA_SEL_CLUT	BIT(29)

> > +#define DCU_CTRLDESCLN_4_SAFETY_EN	BIT(28)

> > +#define DCU_CTRLDESCLN_4_TRANS(x)	((x) << 20)

> > +#define DCU_CTRLDESCLN_4_BPP(x)		((x) << 16)

> > +#define DCU_CTRLDESCLN_4_RLE_EN		BIT(15)

> > +#define DCU_CTRLDESCLN_4_LUOFFS(x)	((x) << 4)

> > +#define DCU_CTRLDESCLN_4_BB_ON		BIT(2)

> > +#define DCU_CTRLDESCLN_4_AB(x)		(x)

> > +

> > +#define DCU_CTRLDESCLN_5(x)		(0x210 + (x) * 0x40)

> > +#define DCU_CTRLDESCLN_5_CKMAX_R(x)	((x) << 16)

> > +#define DCU_CTRLDESCLN_5_CKMAX_G(x)	((x) << 8)

> > +#define DCU_CTRLDESCLN_5_CKMAX_B(x)	(x)

> > +

> > +#define DCU_CTRLDESCLN_6(x)		(0x214 + (x) * 0x40)

> > +#define DCU_CTRLDESCLN_6_CKMIN_R(x)	((x) << 16)

> > +#define DCU_CTRLDESCLN_6_CKMIN_G(x)	((x) << 8)

> > +#define DCU_CTRLDESCLN_6_CKMIN_B(x)	(x)

> > +

> > +#define DCU_CTRLDESCLN_7(x)		(0x218 + (x) * 0x40)

> > +#define DCU_CTRLDESCLN_7_TILE_VER(x)	((x) << 16)

> > +#define DCU_CTRLDESCLN_7_TILE_HOR(x)	(x)

> > +

> > +#define DCU_CTRLDESCLN_8(x)		(0x21c + (x) * 0x40)

> > +#define DCU_CTRLDESCLN_8_FG_FCOLOR(x)	(x)

> > +

> > +#define DCU_CTRLDESCLN_9(x)		(0x220 + (x) * 0x40)

> > +#define DCU_CTRLDESCLN_9_BG_BCOLOR(x)	(x)

> > +

> > +#define DCU_CTRLDESCLN_10(x)		(0x224 + (x) * 0x40)

> > +#define DCU_CTRLDESCLN_10_POST_SKIP(x)	((x) << 16)

> > +#define DCU_CTRLDESCLN_10_PRE_SKIP(x)	(x)

> > +

> > +#define FSL_DCU_RGB565			4

> > +#define FSL_DCU_RGB888			5

> > +#define FSL_DCU_ARGB8888		6

> > +#define FSL_DCU_ARGB1555		11

> > +#define FSL_DCU_ARGB4444		12

> > +#define FSL_DCU_YUV422			14

> > +

> > +#define TCON_CTRL1			0x0000

> > +#define TCON_BYPASS_ENABLE		BIT(29)

> > +

> > +#define DBG(fmt, ...) DRM_DEBUG(fmt"\n", ##__VA_ARGS__)

> > +

> > +struct clk;

> > +struct device;

> > +struct drm_device;

> > +

> > +struct fsl_dcu_drm_device {

> > +	struct device *dev;

> > +	struct device_node *np;

> > +	struct regmap *regmap;

> > +	struct regmap *tcon_regmap;

> > +	unsigned int irq;

> > +	struct clk *clk;

> > +	/*protects hardware register*/

> > +	spinlock_t irq_lock;

> > +	struct drm_device *ddev;

> > +	struct drm_fbdev_cma *fbdev;

> > +	struct fsl_dcu_drm_crtc crtc;

> > +	struct drm_encoder encoder;

> > +	struct fsl_dcu_drm_connector connector;

> > +};

> > +

> > +void fsl_dcu_fbdev_init(struct drm_device *dev);

> > +

> > +#endif /* __FSL_DCU_DRM_DRV_H__ */

> > diff --git a/drivers/gpu/drm/fsl/fsl_dcu_drm_fbdev.c

> > b/drivers/gpu/drm/fsl/fsl_dcu_drm_fbdev.c

> > new file mode 100644

> > index 0000000..f8ef0e1

> > --- /dev/null

> > +++ b/drivers/gpu/drm/fsl/fsl_dcu_drm_fbdev.c

> > @@ -0,0 +1,26 @@

> > +/*

> > + * Copyright 2015 Freescale Semiconductor, Inc.

> > + *

> > + * 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.

> > + *

> > + * This program is distributed in the hope that it will be useful, but

> WITHOUT

> > + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY

> or

> > + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public

> License for

> > + * more details.

> > + *

> > + */

> > +

> > +#include <drm/drmP.h>

> > +#include <drm/drm_fb_cma_helper.h>

> > +

> > +#include "fsl_dcu_drm_drv.h"

> > +

> > +/* initialize fbdev helper */

> > +void fsl_dcu_fbdev_init(struct drm_device *dev)

> > +{

> > +	struct fsl_dcu_drm_device *fsl_dev = dev_get_drvdata(dev->dev);

> > +

> > +	fsl_dev->fbdev = drm_fbdev_cma_init(dev, 24, 1, 1);

> > +}

> > diff --git a/drivers/gpu/drm/fsl/fsl_dcu_drm_kms.c

> > b/drivers/gpu/drm/fsl/fsl_dcu_drm_kms.c

> > new file mode 100644

> > index 0000000..0de21c6

> > --- /dev/null

> > +++ b/drivers/gpu/drm/fsl/fsl_dcu_drm_kms.c

> > @@ -0,0 +1,42 @@

> > +/*

> > + * Copyright 2015 Freescale Semiconductor, Inc.

> > + *

> > + * Freescale DCU drm device driver

> > + *

> > + * 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 "fsl_dcu_drm_crtc.h"

> > +#include "fsl_dcu_drm_connector.h"

> > +#include "fsl_dcu_drm_drv.h"

> > +

> > +static const struct drm_mode_config_funcs fsl_dcu_drm_mode_config_funcs

> = {

> > +	.fb_create = drm_fb_cma_create,

> > +	.atomic_check = drm_atomic_helper_check,

> > +	.atomic_commit = drm_atomic_helper_commit,

> > +};

> > +

> > +int fsl_dcu_drm_modeset_init(struct fsl_dcu_drm_device *fsl_dev)

> > +{

> > +	drm_mode_config_init(fsl_dev->ddev);

> > +

> > +	fsl_dev->ddev->mode_config.min_width = 0;

> > +	fsl_dev->ddev->mode_config.min_height = 0;

> > +	fsl_dev->ddev->mode_config.max_width = 2031;

> > +	fsl_dev->ddev->mode_config.max_height = 2047;

> > +	fsl_dev->ddev->mode_config.funcs = &fsl_dcu_drm_mode_config_funcs;

> > +

> > +	drm_kms_helper_poll_init(fsl_dev->ddev);

> > +	fsl_dcu_drm_crtc_create(fsl_dev);

> > +	fsl_dcu_drm_encoder_create(fsl_dev, &fsl_dev->crtc);

> > +	fsl_dcu_drm_connector_create(fsl_dev, &fsl_dev->encoder);

> > +	drm_mode_config_reset(fsl_dev->ddev);

> > +

> > +	return 0;

> > +}

> > diff --git a/drivers/gpu/drm/fsl/fsl_dcu_drm_kms.h

> > b/drivers/gpu/drm/fsl/fsl_dcu_drm_kms.h

> > new file mode 100644

> > index 0000000..b9bd299

> > --- /dev/null

> > +++ b/drivers/gpu/drm/fsl/fsl_dcu_drm_kms.h

> > @@ -0,0 +1,17 @@

> > +/*

> > + * Copyright 2015 Freescale Semiconductor, Inc.

> > + *

> > + * Freescale DCU drm device driver

> > + *

> > + * 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 __FSL_DCU_DRM_KMS_H__

> > +#define __FSL_DCU_DRM_KMS_H__

> > +

> > +int fsl_dcu_drm_modeset_init(struct fsl_dcu_drm_device *fsl_dev);

> > +

> > +#endif /* __FSL_DCU_DRM_KMS_H__ */

> > diff --git a/drivers/gpu/drm/fsl/fsl_dcu_drm_plane.c

> > b/drivers/gpu/drm/fsl/fsl_dcu_drm_plane.c

> > new file mode 100644

> > index 0000000..6146e80

> > --- /dev/null

> > +++ b/drivers/gpu/drm/fsl/fsl_dcu_drm_plane.c

> > @@ -0,0 +1,192 @@

> > +/*

> > + * Copyright 2015 Freescale Semiconductor, Inc.

> > + *

> > + * Freescale DCU drm device driver

> > + *

> > + * 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_crtc.h>

> > +#include <drm/drm_crtc_helper.h>

> > +#include <drm/drm_fb_cma_helper.h>

> > +#include <drm/drm_gem_cma_helper.h>

> > +#include <linux/regmap.h>

> > +#include <drm/drm_plane_helper.h>

> > +#include <drm/drm_atomic_helper.h>

> > +

> > +#include "fsl_dcu_drm_drv.h"

> > +#include "fsl_dcu_drm_kms.h"

> > +#include "fsl_dcu_drm_plane.h"

> > +

> > +#define to_fsl_dcu_plane(plane) \

> > +	container_of(plane, struct fsl_dcu_drm_plane, plane)

> > +

> > +static int

> > +fsl_dcu_drm_plane_prepare_fb(struct drm_plane *plane,

> > +			     struct drm_framebuffer *fb,

> > +			     const struct drm_plane_state *new_state)

> > +{

> > +	return 0;

> > +}

> > +

> > +static void

> > +fsl_dcu_drm_plane_cleanup_fb(struct drm_plane *plane,

> > +			     struct drm_framebuffer *fb,

> > +			     const struct drm_plane_state *new_state)

> > +{

> > +}

> > +

> > +static int fsl_dcu_drm_plane_atomic_check(struct drm_plane *plane,

> > +					  struct drm_plane_state *state)

> > +{

> > +	return 0;

> > +}

> > +

> > +static void fsl_dcu_drm_plane_atomic_disable(struct drm_plane *plane,

> > +					     struct drm_plane_state *old_state)

> > +{

> > +}

> > +

> > +void fsl_dcu_drm_plane_atomic_update(struct drm_plane *plane,

> > +				     struct drm_plane_state *old_state)

> > +{

> > +	struct fsl_dcu_drm_device *fsl_dev = plane->dev->dev_private;

> > +	struct drm_plane_state *state = plane->state;

> > +	struct drm_framebuffer *fb = plane->state->fb;

> > +	u32 index, alpha, bpp;

> > +	struct drm_gem_cma_object *gem;

> > +	struct fsl_dcu_drm_plane *fsl_plane = to_fsl_dcu_plane(plane);

> > +

> > +	index = fsl_plane->index;

> > +	gem = drm_fb_cma_get_gem_obj(fb, 0);

> > +

> > +	switch (fb->pixel_format) {

> > +	case DRM_FORMAT_RGB565:

> > +		bpp = FSL_DCU_RGB565;

> > +		alpha = 0xff;

> > +		break;

> > +	case DRM_FORMAT_RGB888:

> > +		bpp = FSL_DCU_RGB888;

> > +		alpha = 0xff;

> > +		break;

> > +	case DRM_FORMAT_ARGB8888:

> > +		bpp = FSL_DCU_ARGB8888;

> > +		alpha = 0xff;

> > +		break;

> > +	case DRM_FORMAT_BGRA4444:

> > +		bpp = FSL_DCU_ARGB4444;

> > +		alpha = 0xff;

> > +		break;

> > +	case DRM_FORMAT_ARGB1555:

> > +		bpp = FSL_DCU_ARGB1555;

> > +		alpha = 0xff;

> > +		break;

> > +	case DRM_FORMAT_YUV422:

> > +		bpp = FSL_DCU_YUV422;

> > +		alpha = 0xff;

> > +		break;

> > +	default:

> > +		return;

> > +	}

> > +

> > +	regmap_write(fsl_dev->regmap, DCU_CTRLDESCLN_1(index),

> > +		     DCU_CTRLDESCLN_1_HEIGHT(state->crtc_h) |

> > +		     DCU_CTRLDESCLN_1_WIDTH(state->crtc_w));

> > +	regmap_write(fsl_dev->regmap, DCU_CTRLDESCLN_2(index),

> > +		     DCU_CTRLDESCLN_2_POSY(state->crtc_y) |

> > +		     DCU_CTRLDESCLN_2_POSX(state->crtc_x));

> > +	regmap_write(fsl_dev->regmap, DCU_CTRLDESCLN_3(index), gem->paddr);

> > +	regmap_write(fsl_dev->regmap, DCU_CTRLDESCLN_4(index),

> > +		     DCU_CTRLDESCLN_4_EN |

> > +		     DCU_CTRLDESCLN_4_TRANS(alpha) |

> > +		     DCU_CTRLDESCLN_4_BPP(bpp) |

> > +		     DCU_CTRLDESCLN_4_AB(0));

> > +	regmap_write(fsl_dev->regmap, DCU_CTRLDESCLN_5(index),

> > +		     DCU_CTRLDESCLN_5_CKMAX_R(0xFF) |

> > +		     DCU_CTRLDESCLN_5_CKMAX_G(0xFF) |

> > +		     DCU_CTRLDESCLN_5_CKMAX_B(0xFF));

> > +	regmap_write(fsl_dev->regmap, DCU_CTRLDESCLN_6(index),

> > +		     DCU_CTRLDESCLN_6_CKMIN_R(0) |

> > +		     DCU_CTRLDESCLN_6_CKMIN_G(0) |

> > +		     DCU_CTRLDESCLN_6_CKMIN_B(0));

> > +	regmap_write(fsl_dev->regmap, DCU_CTRLDESCLN_7(index), 0);

> > +	regmap_write(fsl_dev->regmap, DCU_CTRLDESCLN_8(index),

> > +		     DCU_CTRLDESCLN_8_FG_FCOLOR(0));

> > +	regmap_write(fsl_dev->regmap, DCU_CTRLDESCLN_9(index),

> > +		     DCU_CTRLDESCLN_9_BG_BCOLOR(0));

> > +	if (of_device_is_compatible(fsl_dev->np, "fsl,ls1021a-dcu"))

> > +		regmap_write(fsl_dev->regmap, DCU_CTRLDESCLN_10(index),

> > +			     DCU_CTRLDESCLN_10_POST_SKIP(0) |

> > +			     DCU_CTRLDESCLN_10_PRE_SKIP(0));

> > +	regmap_update_bits(fsl_dev->regmap, DCU_DCU_MODE,

> > +			   DCU_MODE_DCU_MODE_MASK,

> > +			   DCU_MODE_DCU_MODE(DCU_MODE_NORMAL));

> > +	regmap_write(fsl_dev->regmap, DCU_UPDATE_MODE,

> DCU_UPDATE_MODE_READREG);

> > +}

> > +

> > +int fsl_dcu_drm_plane_disable(struct drm_plane *plane)

> > +{

> > +	return 0;

> > +}

> > +

> > +void fsl_dcu_drm_plane_destroy(struct drm_plane *plane)

> > +{

> > +	fsl_dcu_drm_plane_disable(plane);

> > +	drm_plane_cleanup(plane);

> > +}

> > +

> > +static const uint32_t fsl_dcu_drm_plane_formats[] = {

> > +	DRM_FORMAT_RGB565,

> > +	DRM_FORMAT_RGB888,

> > +	DRM_FORMAT_ARGB8888,

> > +	DRM_FORMAT_ARGB4444,

> > +	DRM_FORMAT_ARGB1555,

> > +	DRM_FORMAT_YUV422,

> > +};

> > +

> > +static const struct drm_plane_funcs fsl_dcu_drm_plane_funcs = {

> > +	.update_plane = drm_atomic_helper_update_plane,

> > +	.disable_plane = drm_atomic_helper_disable_plane,

> > +	.destroy = fsl_dcu_drm_plane_destroy,

> > +	.atomic_duplicate_state = drm_atomic_helper_plane_duplicate_state,

> > +	.atomic_destroy_state = drm_atomic_helper_plane_destroy_state,

> > +	.reset = drm_atomic_helper_plane_reset,

> > +};

> > +

> > +static const struct drm_plane_helper_funcs

> fsl_dcu_drm_plane_helper_funcs = {

> > +	.prepare_fb = fsl_dcu_drm_plane_prepare_fb,

> > +	.cleanup_fb = fsl_dcu_drm_plane_cleanup_fb,

> > +	.atomic_check = fsl_dcu_drm_plane_atomic_check,

> > +	.atomic_update = fsl_dcu_drm_plane_atomic_update,

> > +	.atomic_disable = fsl_dcu_drm_plane_atomic_disable,

> > +};

> > +

> > +struct drm_plane *fsl_dcu_drm_primary_create_plane(struct drm_device

> *dev)

> > +{

> > +	struct drm_plane *primary;

> > +	int ret;

> > +

> > +	primary = kzalloc(sizeof(*primary), GFP_KERNEL);

> > +	if (!primary) {

> > +		DRM_DEBUG_KMS("Failed to allocate primary plane\n");

> > +		return NULL;

> > +	}

> > +

> > +	/* possible_crtc's will be filled in later by crtc_init */

> > +	ret = drm_universal_plane_init(dev, primary, 0,

> > +				       &fsl_dcu_drm_plane_funcs,

> > +				       fsl_dcu_drm_plane_formats,

> > +				       ARRAY_SIZE(fsl_dcu_drm_plane_formats),

> > +				       DRM_PLANE_TYPE_PRIMARY);

> > +	if (ret) {

> > +		kfree(primary);

> > +		primary = NULL;

> > +	}

> > +	drm_plane_helper_add(primary, &fsl_dcu_drm_plane_helper_funcs);

> > +

> > +	return primary;

> > +}

> > diff --git a/drivers/gpu/drm/fsl/fsl_dcu_drm_plane.h

> > b/drivers/gpu/drm/fsl/fsl_dcu_drm_plane.h

> > new file mode 100644

> > index 0000000..ccbfa61

> > --- /dev/null

> > +++ b/drivers/gpu/drm/fsl/fsl_dcu_drm_plane.h

> > @@ -0,0 +1,23 @@

> > +/*

> > + * Copyright 2015 Freescale Semiconductor, Inc.

> > + *

> > + * Freescale DCU drm device driver

> > + *

> > + * 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 __FSL_DCU_DRM_PLANE_H__

> > +#define __FSL_DCU_DRM_PLANE_H__

> > +

> > +struct fsl_dcu_drm_device;

> > +struct fsl_dcu_drm_plane {

> > +	struct drm_plane plane;

> > +	unsigned int index;

> > +};

> > +

> > +struct drm_plane *fsl_dcu_drm_primary_create_plane(struct drm_device

> *dev);

> > +

> > +#endif /* __FSL_DCU_DRM_PLANE_H__ */
Stefan Agner April 7, 2015, 12:12 p.m. UTC | #3
Hi Jianwei,

On 2015-04-07 08:44, Jianwei.Wang@freescale.com wrote:
> Hi Stefan,
> 
> Thank you for your review and testing on Vybrid F610 device. This driver 
> just implement the basic functions and it only support the exported 
> framebuffer access. Some DRM interfaces are not implemented now. So your 
> test result is normal. I will implement these interfaces with patches soon 
> afterwards. I don't plan to add new features for the initial version driver,
> otherwise it will be a long term for this version.
> 
> I tested on ls1021a using TFT panel, there are no flickers on the screen
> when inserting a USB HID device. I will do more test if time permits.
> 
> By the way, could please give me some guidance on how X-Server use DRM 
> Interface directly? Do you have some papers or webpage about this?

I'm using the modesetting X.org driver. Lots of distributions ship that
driver as a package (e.g. xserver-xorg-video-modesetting in Debian, or
xf86-video-modesetting in OpenEmbedded). Since 1.17 this driver has even
been included into the main source tree of Xorg X-Server
(http://cgit.freedesktop.org/xorg/xserver/tree/hw/xfree86/drivers/modesetting)

This driver is using KMS/DRM interface and should work well for
un-accelerated graphic devices. This is a a much nicer way to use X.org
on top of a DRM driver, since it avoids going through the legacy fbdev
interface. The man page shows how to use it:
http://linux.die.net/man/4/modesetting

So, when the driver is installed, it is just choosing that driver in
xorg.conf:

Section "Device"
        Identifier      "dcu"
        Driver          "modesetting"
EndSection

Some more comments below...

> 
> My reply below...
> 
>>
>> Hi Jianwei,
>>
>> The driver worked on a Vybrid VF610 device using the exported
>> framebuffer. However, when using X-Server through the DRM interface
>> directly (by using the modesetting driver) I get just a black screen so
>> far, still investigating the reason. What user-space interfaces did you
>> test?
>>
>> When using the FB device and insert a USB HID device, I get some
>> flickers on the screen. I didn't had those on the dcufb driver, did you
>> notice something like this too? Probably related to the resolution, I'm
>> using VGA resolution.
>>
>> Some comments below.
>>
>>
>> On 2015-03-26 06:37, Jianwei Wang wrote:
>> > This patch add support for Two Dimensional Animation and Compositing
>> > Engine (2D-ACE) on the Freescale SoCs.
>> >
>> > 2D-ACE is a Freescale display controller. 2D-ACE describes
>> > the functionality of the module extremely well its name is a value
>> > that cannot be used as a token in programming languages.
>> > Instead the valid token "DCU" is used to tag the register names and
>> > function names.
>> >
>> > The Display Controller Unit (DCU) module is a system master that
>> > fetches graphics stored in internal or external memory and displays
>> > them on a TFT LCD panel. A wide range of panel sizes is supported
>> > and the timing of the interface signals is highly configurable.
>> > Graphics are read directly from memory and then blended in real-time,
>> > which allows for dynamic content creation with minimal CPU
>> > intervention.
>> >
>> > The features:
>> > (1) Full RGB888 output to TFT LCD panel.
>> > (2) For the current LCD panel, WQVGA "480x272" is supported.
>> > (3) Blending of each pixel using up to 4 source layers
>> > dependent on size of panel.
>>
>> modetest only shows one layer currently...
> 
> Yes, only one plane and one framebuffer were created now, others
> maybe create as user requirement or create all when initializing,
> I'm not sure now. This describe the hardware feature
> 
>>
>> > (4) Each graphic layer can be placed with one pixel resolution
>> > in either axis.
>> > (5) Each graphic layer support RGB565 and RGB888 direct colors
>> > without alpha channel
>> > and BGRA8888 direct colors with an alpha channel.
>>
>> The array fsl_dcu_drm_plane_formats below shows more formats, does this
>> commit log needs updating?
>>
> 
> I agree with your suggestion, I will update this commit log
> 
>> > (6) Each graphic layer support alpha blending with 8-bit
>> > resolution.
>> >
>> > This is a simplified version, only one primary plane, one
>> > framebuffer created for fbdev, one crtc, one connector for
>> > TFT LCD panel, an encoder.
>> >
>> > Signed-off-by: Alison Wang <b18965@freescale.com>
>> > Signed-off-by: Xiubo Li <lixiubo@cmss.chinamobile.com>
>> > Signed-off-by: Jianwei Wang <b52261@freescale.com>
>> > ---
>> >
>> > Changed in V3:
>> >
>> > - Test driver on Vybrid board and add compatible string
>> > - Remove unused functions
>> > - set default crtc for encoder
>> > - replace legacy functions with atomic help functions
>> > - Set the unique name of the DRM device
>> > - Implement irq handle function for vblank interrupt
>> >
>> > Changed in v2:
>> > - Add atomic support
>> > - Modify bindings file
>> > - Rename node for compatibility
>> > - Move platform related code out for compatibility
>> >
>> >  .../devicetree/bindings/drm/fsl/fsl,dcu.txt        |  50 ++++
>> >  drivers/gpu/drm/Kconfig                            |   2 +
>> >  drivers/gpu/drm/Makefile                           |   1 +
>> >  drivers/gpu/drm/fsl/Kconfig                        |  17 ++
>> >  drivers/gpu/drm/fsl/Makefile                       |   8 +
>> >  drivers/gpu/drm/fsl/fsl_dcu_drm_connector.c        | 193 ++++++++++++
>> >  drivers/gpu/drm/fsl/fsl_dcu_drm_connector.h        |  30 ++
>> >  drivers/gpu/drm/fsl/fsl_dcu_drm_crtc.c             | 165 ++++++++++
>> >  drivers/gpu/drm/fsl/fsl_dcu_drm_crtc.h             |  26 ++
>> >  drivers/gpu/drm/fsl/fsl_dcu_drm_drv.c              | 331
>> +++++++++++++++++++++
>> >  drivers/gpu/drm/fsl/fsl_dcu_drm_drv.h              | 210 +++++++++++++
>> >  drivers/gpu/drm/fsl/fsl_dcu_drm_fbdev.c            |  26 ++
>> >  drivers/gpu/drm/fsl/fsl_dcu_drm_kms.c              |  42 +++
>> >  drivers/gpu/drm/fsl/fsl_dcu_drm_kms.h              |  17 ++
>> >  drivers/gpu/drm/fsl/fsl_dcu_drm_plane.c            | 192 ++++++++++++
>> >  drivers/gpu/drm/fsl/fsl_dcu_drm_plane.h            |  23 ++
>> >  16 files changed, 1333 insertions(+)
>> >  create mode 100644
>> Documentation/devicetree/bindings/drm/fsl/fsl,dcu.txt
>> >  create mode 100644 drivers/gpu/drm/fsl/Kconfig
>> >  create mode 100644 drivers/gpu/drm/fsl/Makefile
>> >  create mode 100644 drivers/gpu/drm/fsl/fsl_dcu_drm_connector.c
>> >  create mode 100644 drivers/gpu/drm/fsl/fsl_dcu_drm_connector.h
>> >  create mode 100644 drivers/gpu/drm/fsl/fsl_dcu_drm_crtc.c
>> >  create mode 100644 drivers/gpu/drm/fsl/fsl_dcu_drm_crtc.h
>> >  create mode 100644 drivers/gpu/drm/fsl/fsl_dcu_drm_drv.c
>> >  create mode 100644 drivers/gpu/drm/fsl/fsl_dcu_drm_drv.h
>> >  create mode 100644 drivers/gpu/drm/fsl/fsl_dcu_drm_fbdev.c
>> >  create mode 100644 drivers/gpu/drm/fsl/fsl_dcu_drm_kms.c
>> >  create mode 100644 drivers/gpu/drm/fsl/fsl_dcu_drm_kms.h
>> >  create mode 100644 drivers/gpu/drm/fsl/fsl_dcu_drm_plane.c
>> >  create mode 100644 drivers/gpu/drm/fsl/fsl_dcu_drm_plane.h
>> >
>> > diff --git a/Documentation/devicetree/bindings/drm/fsl/fsl,dcu.txt
>> > b/Documentation/devicetree/bindings/drm/fsl/fsl,dcu.txt
>> > new file mode 100644
>> > index 0000000..bdc7d5b
>> > --- /dev/null
>> > +++ b/Documentation/devicetree/bindings/drm/fsl/fsl,dcu.txt
>> > @@ -0,0 +1,50 @@
>> > +Device Tree bindings for Freescale DCU DRM Driver
>> > +
>> > +Required properties:
>> > +- compatible:           Should be one of
>> > +	* "fsl,ls1021a-dcu".
>> > +	* "fsl,vf610-dcu".
>>
>> In the Vybrid reference manual, that IP is denoted as "DCU4". Any reason
>> why you left out the DCU version? Is this different for LS1021a? On the
>> other hand, with the SoC in the name, the IP should be specified clear
>> enough.
>>
> 
> In the LS1021A reference manual, no DCU version related words. I asked
> previous DCU owner, she told me that LS1021A use DCU5 and she also point
> out that the same DCU version there may be differences between different 
> SoCs. So I named compatible string with SoC name.

Ok, I'm fine with that, thx for the background information.

> 
>> > +- reg:                  Address and length of the register set for dcu.
>> > +- clocks:               From common clock binding: handle to dcu clock.
>> > +- clock-names:          From common clock binding: Shall be "dcu".
>> > +- display:              The phandle to display node.
>> > +
>> > +Required properties:
>> > +- bits-per-pixel:       <16> for RGB565,
>> > +			<24> for RGB888,
>> > +			<32> for RGB8888.
>> > +
>> > +Required timing node for dispplay sub-node:
>> > +- display-timings:      Refer to binding doc display-timing.txt for
>> details.
>> > +
>> > +Examples:
>> > +dcu: dcu@2ce0000 {
>> > +	compatible = "fsl,ls1021a-dcu";
>> > +	reg = <0x0 0x2ce0000 0x0 0x10000>;
>> > +	clocks = <&platform_clk 0>;
>> > +	clock-names = "dcu";
>> > +	big-endian;
>> > +	display = <&display>;
>> > +
>> > +	display: display@0 {
>> > +		bits-per-pixel = <24>;
>> > +
>> > +		display-timings {
>> > +			native-mode = <&timing0>;
>> > +			timing0: nl4827hc19 {
>> > +				clock-frequency = <10870000>;
>> > +				hactive = <480>;
>> > +				vactive = <272>;
>> > +				hback-porch = <2>;
>> > +				hfront-porch = <2>;
>> > +				vback-porch = <1>;
>> > +				vfront-porch = <1>;
>> > +				hsync-len = <41>;
>> > +				vsync-len = <2>;
>> > +				hsync-active = <1>;
>> > +				vsync-active = <1>;
>> > +			};
>> > +		};
>> > +	};
>> > +};
>> > +
>> > diff --git a/drivers/gpu/drm/Kconfig b/drivers/gpu/drm/Kconfig
>> > index 151a050..a6957aa 100644
>> > --- a/drivers/gpu/drm/Kconfig
>> > +++ b/drivers/gpu/drm/Kconfig
>> > @@ -199,6 +199,8 @@ source "drivers/gpu/drm/bochs/Kconfig"
>> >
>> >  source "drivers/gpu/drm/msm/Kconfig"
>> >
>> > +source "drivers/gpu/drm/fsl/Kconfig"
>> > +
>> >  source "drivers/gpu/drm/tegra/Kconfig"
>> >
>> >  source "drivers/gpu/drm/panel/Kconfig"
>> > diff --git a/drivers/gpu/drm/Makefile b/drivers/gpu/drm/Makefile
>> > index 2c239b9..ab5b9ef 100644
>> > --- a/drivers/gpu/drm/Makefile
>> > +++ b/drivers/gpu/drm/Makefile
>> > @@ -56,6 +56,7 @@ obj-$(CONFIG_DRM_UDL) += udl/
>> >  obj-$(CONFIG_DRM_AST) += ast/
>> >  obj-$(CONFIG_DRM_ARMADA) += armada/
>> >  obj-$(CONFIG_DRM_ATMEL_HLCDC)	+= atmel-hlcdc/
>> > +obj-$(CONFIG_DRM_FSL_DCU) += fsl/
>>
>> Hm, I'm wondering whether it would be a good idea to store that driver
>> under fsl-dcu/... Any opinion?
>>
> 
> I think it is good advice, I'll think about this
> 
>> >  obj-$(CONFIG_DRM_RCAR_DU) += rcar-du/
>> >  obj-$(CONFIG_DRM_SHMOBILE) +=shmobile/
>> >  obj-$(CONFIG_DRM_OMAP)	+= omapdrm/
>> > diff --git a/drivers/gpu/drm/fsl/Kconfig b/drivers/gpu/drm/fsl/Kconfig
>> > new file mode 100644
>> > index 0000000..e4f8df0
>> > --- /dev/null
>> > +++ b/drivers/gpu/drm/fsl/Kconfig
>> > @@ -0,0 +1,17 @@
>> > +config DRM_FSL_DCU
>> > +	tristate "DRM Support for Freescale DCU"
>> > +	depends on DRM && OF && ARM
>> > +	select DRM_KMS_HELPER
>> > +	select DRM_KMS_CMA_HELPER
>> > +	select VIDEOMODE_HELPERS
>> > +	select BACKLIGHT_CLASS_DEVICE
>> > +	select BACKLIGHT_LCD_SUPPORT
>> > +	select REGMAP_MMIO
>> > +	select DRM_KMS_FB_HELPER
>> > +	select FB_SYS_FILLRECT
>> > +	select FB_SYS_COPYAREA
>> > +	select FB_SYS_IMAGEBLIT
>> > +	select FB_SYS_FOPS
>> > +	help
>> > +	  Choose this option if you have an Freescale DCU chipset.
>> > +	  If M is selected the module will be called fsl-dcu-drm.
>> > diff --git a/drivers/gpu/drm/fsl/Makefile b/drivers/gpu/drm/fsl/Makefile
>> > new file mode 100644
>> > index 0000000..5f74aee
>> > --- /dev/null
>> > +++ b/drivers/gpu/drm/fsl/Makefile
>> > @@ -0,0 +1,8 @@
>> > +fsl-dcu-drm-y := fsl_dcu_drm_drv.o \
>> > +	       fsl_dcu_drm_kms.o \
>> > +	       fsl_dcu_drm_connector.o \
>> > +	       fsl_dcu_drm_plane.o \
>> > +	       fsl_dcu_drm_crtc.o \
>> > +	       fsl_dcu_drm_fbdev.o \
>> > +
>> > +obj-$(CONFIG_DRM_FSL_DCU)	+= fsl-dcu-drm.o
>> > diff --git a/drivers/gpu/drm/fsl/fsl_dcu_drm_connector.c
>> > b/drivers/gpu/drm/fsl/fsl_dcu_drm_connector.c
>> > new file mode 100644
>> > index 0000000..4610647
>> > --- /dev/null
>> > +++ b/drivers/gpu/drm/fsl/fsl_dcu_drm_connector.c
>> > @@ -0,0 +1,193 @@
>> > +/*
>> > + * Copyright 2015 Freescale Semiconductor, Inc.
>> > + *
>> > + * Freescale DCU drm device driver
>> > + *
>> > + * This program is free software; you can redistribute it and/or modify
>> > + * it under the terms of the GNU General Public License as published by
>> > + * the Free Software Foundation; either version 2 of the License, or
>> > + * (at your option) any later version.
>> > + */
>> > +
>> > +#include <linux/backlight.h>
>> > +
>> > +#include <drm/drmP.h>
>> > +#include <drm/drm_atomic_helper.h>
>> > +#include <video/of_display_timing.h>
>> > +
>> > +#include "fsl_dcu_drm_drv.h"
>> > +#include "fsl_dcu_drm_connector.h"
>> > +
>> > +static void fsl_dcu_drm_encoder_dpms(struct drm_encoder *encoder, int
>> mode)
>> > +{
>> > +}
>> > +
>> > +static void fsl_dcu_drm_encoder_mode_prepare(struct drm_encoder
>> *encoder)
>> > +{
>> > +}
>> > +
>> > +static void fsl_dcu_drm_encoder_mode_set(struct drm_encoder *encoder,
>> > +					 struct drm_display_mode *mode,
>> > +					 struct drm_display_mode *adjusted_mode)
>> > +{
>> > +}
>> > +
>> > +static void fsl_dcu_drm_encoder_mode_commit(struct drm_encoder *encoder)
>> > +{
>> > +}
>> > +
>> > +static void fsl_dcu_drm_encoder_disable(struct drm_encoder *encoder)
>> > +{
>> > +}
>> > +
>> > +static int
>> > +fsl_dcu_drm_encoder_atomic_check(struct drm_encoder *encoder,
>> > +				 struct drm_crtc_state *crtc_state,
>> > +				 struct drm_connector_state *conn_state)
>> > +{
>> > +	return 0;
>> > +}
>> > +
>> > +static void fsl_dcu_drm_encoder_destroy(struct drm_encoder *encoder)
>> > +{
>> > +	drm_encoder_cleanup(encoder);
>> > +}
>> > +
>> > +static const struct drm_encoder_helper_funcs encoder_helper_funcs = {
>> > +	.dpms = fsl_dcu_drm_encoder_dpms,
>> > +	.prepare = fsl_dcu_drm_encoder_mode_prepare,
>> > +	.commit = fsl_dcu_drm_encoder_mode_commit,
>> > +	.mode_set = fsl_dcu_drm_encoder_mode_set,
>> > +	.disable = fsl_dcu_drm_encoder_disable,
>> > +	.atomic_check = fsl_dcu_drm_encoder_atomic_check,
>> > +};
>> > +
>> > +static const struct drm_encoder_funcs encoder_funcs = {
>> > +	.destroy = fsl_dcu_drm_encoder_destroy,
>> > +};
>> > +
>> > +int fsl_dcu_drm_encoder_create(struct fsl_dcu_drm_device *fsl_dev,
>> > +			       struct fsl_dcu_drm_crtc *crtc)
>> > +{
>> > +	struct drm_encoder *encoder = &fsl_dev->encoder;
>> > +	int ret;
>> > +
>> > +	ret = drm_encoder_init(fsl_dev->ddev, encoder, &encoder_funcs,
>> > +			       DRM_MODE_ENCODER_LVDS);
>> > +	if (ret < 0)
>> > +		return ret;
>> > +
>> > +	drm_encoder_helper_add(encoder, &encoder_helper_funcs);
>> > +	encoder->crtc = &crtc->crtc;
>> > +
>> > +	return 0;
>> > +}
>> > +
>> > +#define to_fsl_dcu_connector(connector) \
>> > +	container_of(connector, struct fsl_dcu_drm_connector, connector)
>> > +
>> > +static int fsl_dcu_drm_connector_get_modes(struct drm_connector
>> *connector)
>> > +{
>> > +	struct drm_device *dev = connector->dev;
>> > +	struct device_node *display_np, *np = dev->dev->of_node;
>> > +	struct drm_display_mode *mode = drm_mode_create(connector->dev);
>> > +	int num_modes = 0;
>> > +
>> > +	if (np) {
>> > +		display_np = of_parse_phandle(np, "display", 0);
>> > +		if (!display_np) {
>> > +			dev_err(dev->dev, "failed to find display phandle\n");
>> > +			return num_modes;
>> > +		}
>> > +		of_get_drm_display_mode(display_np, mode, OF_USE_NATIVE_MODE);
>> > +		mode->type |= DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED,
>> > +		drm_mode_probed_add(connector, mode);
>> > +		num_modes++;
>> > +	}
>> > +
>> > +	return num_modes;
>> > +}
>> > +
>> > +static int fsl_dcu_drm_connector_mode_valid(struct drm_connector
>> *connector,
>> > +					    struct drm_display_mode *mode)
>> > +{
>> > +	return MODE_OK;
>> > +}
>> > +
>> > +static struct drm_encoder *
>> > +fsl_dcu_drm_connector_best_encoder(struct drm_connector *connector)
>> > +{
>> > +	struct fsl_dcu_drm_connector *fsl_con =
>> to_fsl_dcu_connector(connector);
>> > +
>> > +	return fsl_con->encoder;
>> > +}
>> > +
>> > +static void fsl_dcu_drm_connector_destroy(struct drm_connector
>> *connector)
>> > +{
>> > +	drm_connector_unregister(connector);
>> > +	drm_connector_cleanup(connector);
>> > +}
>> > +
>> > +static enum drm_connector_status
>> > +fsl_dcu_drm_connector_detect(struct drm_connector *connector, bool
>> force)
>> > +{
>> > +	return connector_status_connected;
>> > +}
>> > +
>> > +static const struct drm_connector_funcs fsl_dcu_drm_connector_funcs = {
>> > +	.dpms = drm_atomic_helper_connector_dpms,
>> > +	.reset = drm_atomic_helper_connector_reset,
>> > +	.detect = fsl_dcu_drm_connector_detect,
>> > +	.fill_modes = drm_helper_probe_single_connector_modes,
>> > +	.destroy = fsl_dcu_drm_connector_destroy,
>> > +	.atomic_duplicate_state =
>> drm_atomic_helper_connector_duplicate_state,
>> > +	.atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
>> > +};
>> > +
>> > +static const struct drm_connector_helper_funcs connector_helper_funcs =
>> {
>> > +	.get_modes = fsl_dcu_drm_connector_get_modes,
>> > +	.mode_valid = fsl_dcu_drm_connector_mode_valid,
>> > +	.best_encoder = fsl_dcu_drm_connector_best_encoder,
>> > +};
>> > +
>> > +int fsl_dcu_drm_connector_create(struct fsl_dcu_drm_device *fsl_dev,
>> > +				 struct drm_encoder *encoder)
>> > +{
>> > +	struct drm_connector *connector = &fsl_dev->connector.connector;
>> > +	int ret;
>> > +
>> > +	fsl_dev->connector.encoder = encoder;
>> > +
>> > +	connector->display_info.width_mm = 0;
>> > +	connector->display_info.height_mm = 0;
>> > +
>> > +	ret = drm_connector_init(fsl_dev->ddev, connector,
>> > +				 &fsl_dcu_drm_connector_funcs,
>> > +				 DRM_MODE_CONNECTOR_LVDS);
>> > +	if (ret < 0)
>> > +		return ret;
>> > +
>> > +	connector->dpms = DRM_MODE_DPMS_OFF;
>> > +	drm_connector_helper_add(connector, &connector_helper_funcs);
>> > +	ret = drm_connector_register(connector);
>> > +	if (ret < 0)
>> > +		goto err_cleanup;
>> > +
>> > +	ret = drm_mode_connector_attach_encoder(connector, encoder);
>> > +	if (ret < 0)
>> > +		goto err_sysfs;
>> > +
>> > +	connector->encoder = encoder;
>> > +
>> > +	drm_object_property_set_value
>> > +		(&connector->base, fsl_dev->ddev->mode_config.dpms_property,
>> > +		DRM_MODE_DPMS_OFF);
>> > +
>> > +	return 0;
>> > +
>> > +err_sysfs:
>> > +	drm_connector_unregister(connector);
>> > +err_cleanup:
>> > +	drm_connector_cleanup(connector);
>> > +	return ret;
>> > +}
>> > diff --git a/drivers/gpu/drm/fsl/fsl_dcu_drm_connector.h
>> > b/drivers/gpu/drm/fsl/fsl_dcu_drm_connector.h
>> > new file mode 100644
>> > index 0000000..bbf6d38
>> > --- /dev/null
>> > +++ b/drivers/gpu/drm/fsl/fsl_dcu_drm_connector.h
>> > @@ -0,0 +1,30 @@
>> > +/*
>> > + * Copyright 2015 Freescale Semiconductor, Inc.
>> > + *
>> > + * Freescale DCU drm device driver
>> > + *
>> > + * 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 __FSL_DCU_DRM_CONNECTOR_H__
>> > +#define __FSL_DCU_DRM_CONNECTOR_H__
>> > +
>> > +#include <drm/drmP.h>
>> > +#include <drm/drm_crtc.h>
>> > +#include "fsl_dcu_drm_crtc.h"
>> > +
>> > +struct fsl_dcu_drm_device;
>> > +struct fsl_dcu_drm_connector {
>> > +	struct drm_connector connector;
>> > +	struct drm_encoder *encoder;
>> > +};
>> > +
>> > +int fsl_dcu_drm_encoder_create(struct fsl_dcu_drm_device *fsl_dev,
>> > +			       struct fsl_dcu_drm_crtc *crtc);
>> > +int fsl_dcu_drm_connector_create(struct fsl_dcu_drm_device *fsl_dev,
>> > +				 struct drm_encoder *encoder);
>> > +
>> > +#endif /* __FSL_DCU_DRM_CONNECTOR_H__ */
>> > diff --git a/drivers/gpu/drm/fsl/fsl_dcu_drm_crtc.c
>> > b/drivers/gpu/drm/fsl/fsl_dcu_drm_crtc.c
>> > new file mode 100644
>> > index 0000000..076e273
>> > --- /dev/null
>> > +++ b/drivers/gpu/drm/fsl/fsl_dcu_drm_crtc.c
>> > @@ -0,0 +1,165 @@
>> > +/*
>> > + * Copyright 2015 Freescale Semiconductor, Inc.
>> > + *
>> > + * Freescale DCU drm device driver
>> > + *
>> > + * This program is free software; you can redistribute it and/or modify
>> > + * it under the terms of the GNU General Public License as published by
>> > + * the Free Software Foundation; either version 2 of the License, or
>> > + * (at your option) any later version.
>> > + */
>> > +
>> > +#include <linux/regmap.h>
>> > +#include <linux/clk.h>
>> > +
>> > +#include <drm/drmP.h>
>> > +#include <drm/drm_atomic.h>
>> > +#include <drm/drm_atomic_helper.h>
>> > +#include <drm/drm_crtc.h>
>> > +
>> > +#include "fsl_dcu_drm_crtc.h"
>> > +#include "fsl_dcu_drm_drv.h"
>> > +#include "fsl_dcu_drm_plane.h"
>> > +
>> > +#define to_fsl_dcu_crtc(c)	container_of(c, struct fsl_dcu_drm_crtc,
>> crtc)
>> > +
>> > +void fsl_dcu_drm_crtc_suspend(struct drm_crtc *crtc)
>> > +{
>> > +}
>> > +
>> > +static void fsl_dcu_drm_crtc_mode_set_nofb(struct drm_crtc *crtc)
>> > +{
>> > +	struct drm_device *dev = crtc->dev;
>> > +	struct fsl_dcu_drm_device *fsl_dev = dev->dev_private;
>> > +	struct drm_display_mode *mode = &crtc->state->mode;
>> > +	uint32_t hbp, hfp, hsw, vbp, vfp, vsw, div, index;
>> > +
>> > +	DBG(": set mode: %d:\"%s\" %d %d %d %d %d %d %d %d %d %d 0x%x 0x%x",
>> > +	    mode->base.id, mode->name,
>> > +	    mode->vrefresh, mode->clock,
>> > +	    mode->hdisplay, mode->hsync_start,
>> > +	    mode->hsync_end, mode->htotal,
>> > +	    mode->vdisplay, mode->vsync_start,
>> > +	    mode->vsync_end, mode->vtotal,
>> > +	    mode->type, mode->flags);
>> > +
>> > +	index = drm_crtc_index(crtc);
>> > +	div = (uint32_t)clk_get_rate(fsl_dev->clk) / mode->clock / 1000;
>> > +
>> > +	/* Configure timings: */
>> > +	hbp = mode->htotal - mode->hsync_end;
>> > +	hfp = mode->hsync_start - mode->hdisplay;
>> > +	hsw = mode->hsync_end - mode->hsync_start;
>> > +	vbp = mode->vtotal - mode->vsync_end;
>> > +	vfp = mode->vsync_start - mode->vdisplay;
>> > +	vsw = mode->vsync_end - mode->vsync_start;
>> > +
>> > +	regmap_write(fsl_dev->regmap, DCU_HSYN_PARA,
>> > +		     DCU_HSYN_PARA_BP(hbp) |
>> > +		     DCU_HSYN_PARA_PW(hsw) |
>> > +		     DCU_HSYN_PARA_FP(hfp));
>> > +	regmap_write(fsl_dev->regmap, DCU_VSYN_PARA,
>> > +		     DCU_VSYN_PARA_BP(vbp) |
>> > +		     DCU_VSYN_PARA_PW(vsw) |
>> > +		     DCU_VSYN_PARA_FP(vfp));
>> > +	regmap_write(fsl_dev->regmap, DCU_DISP_SIZE,
>> > +		     DCU_DISP_SIZE_DELTA_Y(mode->vdisplay) |
>> > +		     DCU_DISP_SIZE_DELTA_X(mode->hdisplay));
>> > +	regmap_write(fsl_dev->regmap, DCU_DIV_RATIO, div);
>> > +	regmap_write(fsl_dev->regmap, DCU_UPDATE_MODE,
>> DCU_UPDATE_MODE_READREG);
>> > +}
>> > +
>> > +static bool fsl_dcu_drm_crtc_mode_fixup(struct drm_crtc *crtc,
>> > +					const struct drm_display_mode *mode,
>> > +					struct drm_display_mode *adjusted_mode)
>> > +{
>> > +	return true;
>> > +}
>> > +
>> > +static void fsl_dcu_drm_crtc_prepare(struct drm_crtc *crtc)
>> > +{
>> > +}
>> > +
>> > +/* Now enable the clocks, plane, pipe, and connectors that we set up.
>> */
>> > +static void fsl_dcu_drm_crtc_mode_commit(struct drm_crtc *crtc)
>> > +{
>> > +}
>> > +
>> > +static int fsl_dcu_drm_crtc_atomic_check(struct drm_crtc *crtc,
>> > +					 struct drm_crtc_state *state)
>> > +{
>> > +	return 0;
>> > +}
>> > +
>> > +static void fsl_dcu_drm_crtc_atomic_begin(struct drm_crtc *crtc)
>> > +{
>> > +}
>> > +
>> > +static void fsl_dcu_drm_crtc_atomic_flush(struct drm_crtc *crtc)
>> > +{
>> > +}
>> > +
>> > +static void fsl_dcu_drm_disable_crtc(struct drm_crtc *crtc)
>> > +{
>> > +}
>> > +
>> > +static const struct drm_crtc_funcs fsl_dcu_drm_crtc_funcs = {
>> > +	.page_flip = drm_atomic_helper_page_flip,
>> > +	.set_config = drm_atomic_helper_set_config,
>> > +	.destroy = drm_crtc_cleanup,
>> > +	.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 void fsl_dcu_drm_crtc_dpms(struct drm_crtc *crtc, int mode)
>> > +{
>> > +}
>> > +
>> > +static const struct drm_crtc_helper_funcs fsl_dcu_drm_crtc_helper_funcs
>> = {
>> > +	.disable = fsl_dcu_drm_disable_crtc,
>> > +	.mode_fixup = fsl_dcu_drm_crtc_mode_fixup,
>> > +	.mode_set = drm_helper_crtc_mode_set,
>> > +	.mode_set_nofb = fsl_dcu_drm_crtc_mode_set_nofb,
>> > +	.mode_set_base = drm_helper_crtc_mode_set_base,
>> > +	.prepare = fsl_dcu_drm_crtc_prepare,
>> > +	.commit = fsl_dcu_drm_crtc_mode_commit,
>> > +	.atomic_check = fsl_dcu_drm_crtc_atomic_check,
>> > +	.atomic_begin = fsl_dcu_drm_crtc_atomic_begin,
>> > +	.atomic_flush = fsl_dcu_drm_crtc_atomic_flush,
>> > +	.dpms = fsl_dcu_drm_crtc_dpms,
>> > +};
>> > +
>> > +int fsl_dcu_drm_crtc_create(struct fsl_dcu_drm_device *fsl_dev)
>> > +{
>> > +	struct drm_plane *primary;
>> > +	struct drm_crtc *crtc = &fsl_dev->crtc.crtc;
>> > +	int ret;
>> > +


I hit an issue on some Vybrid devices because the planes have not been
properly initialized. It seems that initialization of planes is required
for Vybrid, something like this was also part of the DCU fbdev driver
submitted by Alison Wang:

+#define DCU_TOTAL_LAYER_NUM    64
 int fsl_dcu_drm_crtc_create(struct fsl_dcu_drm_device *fsl_dev)
 {
        struct drm_plane *primary;
        struct drm_crtc *crtc = &fsl_dev->crtc.crtc;
        int ret;
+       int i;
+
+       for (i = 1; i < DCU_TOTAL_LAYER_NUM; i++) {
+               regmap_write(fsl_dev->regmap, DCU_CTRLDESCLN_1(i), 0);
+               regmap_write(fsl_dev->regmap, DCU_CTRLDESCLN_2(i), 0);
+               regmap_write(fsl_dev->regmap, DCU_CTRLDESCLN_3(i), 0);
+               regmap_write(fsl_dev->regmap, DCU_CTRLDESCLN_4(i), 0);
+               regmap_write(fsl_dev->regmap, DCU_CTRLDESCLN_5(i), 0);
+               regmap_write(fsl_dev->regmap, DCU_CTRLDESCLN_6(i), 0);
+               regmap_write(fsl_dev->regmap, DCU_CTRLDESCLN_7(i), 0);
+               regmap_write(fsl_dev->regmap, DCU_CTRLDESCLN_8(i), 0);
+               regmap_write(fsl_dev->regmap, DCU_CTRLDESCLN_9(i), 0);
+       }
+       regmap_write(fsl_dev->regmap, DCU_UPDATE_MODE,
DCU_UPDATE_MODE_READREG);
 
        fsl_dev->crtc.dpms = DRM_MODE_DPMS_OFF;


Not sure if this is required for ls1021a too...


>> > +	fsl_dev->crtc.dpms = DRM_MODE_DPMS_OFF;
>> > +
>> > +	primary = fsl_dcu_drm_primary_create_plane(fsl_dev->ddev);
>> > +	ret = drm_crtc_init_with_planes(fsl_dev->ddev, crtc, primary, NULL,
>> > +					&fsl_dcu_drm_crtc_funcs);
>> > +	if (ret < 0)
>> > +		return ret;
>> > +
>> > +	drm_crtc_helper_add(crtc, &fsl_dcu_drm_crtc_helper_funcs);
>> > +
>> > +	regmap_write(fsl_dev->regmap, DCU_SYN_POL,
>> > +		     DCU_SYN_POL_INV_VS_LOW | DCU_SYN_POL_INV_HS_LOW);
>> > +	regmap_write(fsl_dev->regmap, DCU_BGND, DCU_BGND_R(0) |
>> > +		     DCU_BGND_G(0) | DCU_BGND_B(0));
>> > +	regmap_write(fsl_dev->regmap, DCU_DCU_MODE,
>> > +		     DCU_MODE_BLEND_ITER(1) | DCU_MODE_RASTER_EN);
>> > +	regmap_write(fsl_dev->regmap, DCU_THRESHOLD,
>> > +		     DCU_THRESHOLD_LS_BF_VS(BF_VS_VAL) |
>> > +		     DCU_THRESHOLD_OUT_BUF_HIGH(BUF_MAX_VAL) |
>> > +		     DCU_THRESHOLD_OUT_BUF_LOW(BUF_MIN_VAL));
>> > +	regmap_update_bits(fsl_dev->regmap, DCU_DCU_MODE,
>> > +			   DCU_MODE_DCU_MODE_MASK,
>> > +			   DCU_MODE_DCU_MODE(DCU_MODE_OFF));
>> > +	regmap_write(fsl_dev->regmap, DCU_UPDATE_MODE,
>> DCU_UPDATE_MODE_READREG);
>> > +
>> > +	return 0;
>> > +}
>> > diff --git a/drivers/gpu/drm/fsl/fsl_dcu_drm_crtc.h
>> > b/drivers/gpu/drm/fsl/fsl_dcu_drm_crtc.h
>> > new file mode 100644
>> > index 0000000..d44b564
>> > --- /dev/null
>> > +++ b/drivers/gpu/drm/fsl/fsl_dcu_drm_crtc.h
>> > @@ -0,0 +1,26 @@
>> > +/*
>> > + * Copyright 2015 Freescale Semiconductor, Inc.
>> > + *
>> > + * Freescale DCU drm device driver
>> > + *
>> > + * 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 __FSL_DCU_DRM_CRTC_H__
>> > +#define __FSL_DCU_DRM_CRTC_H__
>> > +
>> > +#include <drm/drmP.h>
>> > +#include <drm/drm_crtc.h>
>> > +
>> > +struct fsl_dcu_drm_device;
>> > +struct fsl_dcu_drm_crtc {
>> > +	struct drm_crtc crtc;
>> > +	int dpms;
>> > +};
>> > +
>> > +int fsl_dcu_drm_crtc_create(struct fsl_dcu_drm_device *fsl_dev);
>> > +
>> > +#endif /* __FSL_DCU_DRM_CRTC_H__ */
>> > diff --git a/drivers/gpu/drm/fsl/fsl_dcu_drm_drv.c
>> > b/drivers/gpu/drm/fsl/fsl_dcu_drm_drv.c
>> > new file mode 100644
>> > index 0000000..d4a559a
>> > --- /dev/null
>> > +++ b/drivers/gpu/drm/fsl/fsl_dcu_drm_drv.c
>> > @@ -0,0 +1,331 @@
>> > +/*
>> > + * Copyright 2015 Freescale Semiconductor, Inc.
>> > + *
>> > + * Freescale DCU drm device driver
>> > + *
>> > + * This program is free software; you can redistribute it and/or modify
>> > + * it under the terms of the GNU General Public License as published by
>> > + * the Free Software Foundation; either version 2 of the License, or
>> > + * (at your option) any later version.
>> > + */
>> > +
>> > +#include <linux/clk.h>
>> > +#include <linux/io.h>
>> > +#include <linux/mm.h>
>> > +#include <linux/module.h>
>> > +#include <linux/of_platform.h>
>> > +#include <linux/platform_device.h>
>> > +#include <linux/pm.h>
>> > +#include <linux/pm_runtime.h>
>> > +#include <linux/regmap.h>
>> > +
>> > +#include <drm/drmP.h>
>> > +#include <linux/fsl/dcu.h>
>>
>> This file seems to be missing in that patch.
>>
>  
> This file in patch 2/4, It's LS1021A platform related code.
> 

This is not allowed in the kernel world: Each commit need to represent a
complete change in the sense of being compileable and runnable. This is
required to bisect kernel issues. Git bisect helps isolate issues by
selecting random commits. If someone is using git bisect, and git
happens to choose to test this exact revision, the developer will sit in
front of a broken kernel. Whenever possible, we try to avoid that.

In this case, you can easily avoid that by moving patch 2/4 in front of
this patch. Then the file will be there when the driver is using it.

However, as I already stated in v2 of the patchset, I don't think that
direct calls into arch are the right solution to enable the pixel clock.
To me, that looks like a clock gate which asks for the common clock
framework being used, e.g. the clk-gate driver:
http://lxr.free-electrons.com/source/drivers/clk/clk-gate.c

The DCU clock gates in Vybrid use this driver too, see:
http://lxr.free-electrons.com/source/arch/arm/mach-imx/clk-vf610.c#L317

--
Stefan


>> > +
>> > +#include "fsl_dcu_drm_drv.h"
>> > +#include "fsl_dcu_drm_kms.h"
>> > +
>> > +static int fsl_dcu_unload(struct drm_device *dev)
>> > +{
>> > +	drm_mode_config_cleanup(dev);
>> > +	drm_vblank_cleanup(dev);
>> > +	drm_irq_uninstall(dev);
>> > +
>> > +	dev->dev_private = NULL;
>> > +
>> > +	return 0;
>> > +}
>> > +
>> > +static struct regmap_config fsl_dcu_regmap_config = {
>> > +	.reg_bits = 32,
>> > +	.reg_stride = 4,
>> > +	.val_bits = 32,
>> > +};
>> > +
>> > +static int fsl_dcu_bypass_tcon(struct fsl_dcu_drm_device *fsl_dev,
>> > +			       struct device_node *np)
>> > +{
>> > +	struct device_node *tcon_np;
>> > +	struct platform_device *pdev;
>> > +	struct clk *tcon_clk;
>> > +	struct resource *res;
>> > +	void __iomem *base;
>> > +
>> > +	tcon_np = of_parse_phandle(np, "tcon-controller", 0);
>> > +	if (!tcon_np)
>> > +		return -EINVAL;
>> > +
>> > +	pdev = of_find_device_by_node(tcon_np);
>> > +	if (!pdev)
>> > +		return -EINVAL;
>> > +
>> > +	tcon_clk = devm_clk_get(&pdev->dev, "tcon");
>> > +	if (IS_ERR(tcon_clk))
>> > +		return PTR_ERR(tcon_clk);
>> > +	clk_prepare_enable(tcon_clk);
>>
>> You enable the clock explicitly...
>>
>> > +
>> > +	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
>> > +	if (!res)
>> > +		return -ENODEV;
>> > +
>> > +	base = devm_ioremap_resource(&pdev->dev, res);
>> > +	if (IS_ERR(base))
>> > +		return PTR_ERR(base);
>> > +
>> > +	fsl_dev->tcon_regmap = devm_regmap_init_mmio_clk(&pdev->dev,
>> > +			"tcon", base, &fsl_dcu_regmap_config);
>>
>> And implicitly using regmap. In a short test on Vybrid, the clock is
>> actually not needed during operation, hence we could use the explicit
>> enabling above, what do you think?
>>
>> Also, the clock and tcon in general currently does not get handled by
>> suspend/resume code...
>>
> 
> OK, I'll update code here
> 
>> > +	if (IS_ERR(fsl_dev->tcon_regmap)) {
>> > +		dev_err(&pdev->dev, "regmap init failed\n");
>> > +		return PTR_ERR(fsl_dev->tcon_regmap);
>> > +	}
>> > +
>> > +	regmap_write(fsl_dev->tcon_regmap, TCON_CTRL1, TCON_BYPASS_ENABLE);
>> > +	return 0;
>> > +}
>> > +
>> > +static int fsl_dcu_drm_irq_init(struct drm_device *dev)
>> > +{
>> > +	struct platform_device *pdev = dev->platformdev;
>> > +	struct fsl_dcu_drm_device *fsl_dev = dev->dev_private;
>> > +	unsigned int int_mask;
>> > +	int ret;
>> > +
>> > +	ret = drm_irq_install(dev, platform_get_irq(dev->platformdev, 0));
>> > +	if (ret < 0)
>> > +		dev_err(&pdev->dev, "failed to install IRQ handler\n");
>> > +
>> > +	dev->irq_enabled = true;
>> > +	dev->vblank_disable_allowed = true;
>> > +
>> > +	regmap_write(fsl_dev->regmap, DCU_INT_STATUS, 0);
>> > +	regmap_read(fsl_dev->regmap, DCU_INT_MASK, &int_mask);
>> > +	regmap_write(fsl_dev->regmap, DCU_INT_MASK, int_mask &
>> > +		     ~DCU_INT_MASK_VBLANK);
>> > +	regmap_write(fsl_dev->regmap, DCU_UPDATE_MODE,
>> DCU_UPDATE_MODE_READREG);
>> > +
>> > +	return 0;
>> > +}
>> > +
>> > +static int fsl_dcu_load(struct drm_device *dev, unsigned long flags)
>> > +{
>> > +	struct platform_device *pdev = dev->platformdev;
>> > +	struct fsl_dcu_drm_device *fsl_dev;
>> > +	struct resource *res;
>> > +	void __iomem *base;
>> > +	int ret;
>> > +
>> > +	fsl_dev = devm_kzalloc(&pdev->dev, sizeof(*fsl_dev), GFP_KERNEL);
>> > +	if (!fsl_dev)
>> > +		return -ENOMEM;
>> > +
>> > +	fsl_dev->dev = &pdev->dev;
>> > +	fsl_dev->ddev = dev;
>> > +	fsl_dev->np = pdev->dev.of_node;
>> > +	dev->dev_private = fsl_dev;
>> > +	drm_dev_set_unique(dev, dev_name(dev->dev));
>> > +
>> > +	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
>> > +	if (!res) {
>> > +		dev_err(&pdev->dev, "could not get memory IO resource\n");
>> > +		return -ENODEV;
>> > +	}
>> > +
>> > +	base = devm_ioremap_resource(&pdev->dev, res);
>> > +	if (IS_ERR(base)) {
>> > +		ret = PTR_ERR(base);
>> > +		return ret;
>> > +	}
>> > +
>> > +	fsl_dev->regmap = devm_regmap_init_mmio_clk(&pdev->dev, NULL,
>> > +			base, &fsl_dcu_regmap_config);
>> > +	if (IS_ERR(fsl_dev->regmap)) {
>> > +		dev_err(&pdev->dev, "regmap init failed\n");
>> > +		return PTR_ERR(fsl_dev->regmap);
>> > +	}
>> > +
>> > +	/* Put TCON in bypass mode, so the input signals from DCU are passed
>> > +	 * through TCON unchanged */
>> > +	fsl_dcu_bypass_tcon(fsl_dev, fsl_dev->np);
>> > +	fsl_dev->clk = devm_clk_get(&pdev->dev, "dcu");
>> > +	if (IS_ERR(fsl_dev->clk)) {
>> > +		ret = PTR_ERR(fsl_dev->clk);
>> > +		dev_err(&pdev->dev, "could not get clock\n");
>> > +		return ret;
>> > +	}
>> > +	clk_prepare_enable(fsl_dev->clk);
>> > +	dev_set_drvdata(dev->dev, fsl_dev);
>> > +
>> > +	ret = fsl_dcu_drm_modeset_init(fsl_dev);
>> > +	if (ret < 0) {
>> > +		dev_err(&pdev->dev, "failed to initialize mode setting\n");
>> > +		return ret;
>> > +	}
>> > +
>> > +	ret = drm_vblank_init(dev, dev->mode_config.num_crtc);
>> > +	if (ret < 0) {
>> > +		dev_err(&pdev->dev, "failed to initialize vblank\n");
>> > +		goto done;
>> > +	}
>> > +
>> > +	ret = fsl_dcu_drm_irq_init(dev);
>> > +	if (ret < 0)
>> > +		goto done;
>> > +
>> > +	fsl_dcu_fbdev_init(dev);
>> > +
>> > +	return 0;
>> > +done:
>> > +	if (ret)
>> > +		fsl_dcu_unload(dev);
>> > +
>> > +	return ret;
>> > +}
>> > +
>> > +static void fsl_dcu_drm_preclose(struct drm_device *dev, struct
>> drm_file *file)
>> > +{
>> > +	;
>> > +}
>> > +
>> > +static irqreturn_t fsl_dcu_drm_irq(int irq, void *arg)
>> > +{
>> > +	struct drm_device *dev = arg;
>> > +	struct fsl_dcu_drm_device *fsl_dev = dev->dev_private;
>> > +	unsigned int int_status;
>> > +
>> > +	regmap_read(fsl_dev->regmap, DCU_INT_STATUS, &int_status);
>> > +	if (int_status & DCU_INT_STATUS_VBLANK)
>> > +		drm_handle_vblank(dev, 0);
>> > +
>> > +	regmap_write(fsl_dev->regmap, DCU_INT_STATUS, 0xffffffff);
>> > +	regmap_write(fsl_dev->regmap, DCU_UPDATE_MODE,
>> DCU_UPDATE_MODE_READREG);
>> > +
>> > +	return IRQ_HANDLED;
>> > +}
>> > +
>> > +static int fsl_dcu_drm_enable_vblank(struct drm_device *dev, int crtc)
>> > +{
>> > +	return 0;
>> > +}
>> > +
>> > +static void fsl_dcu_drm_disable_vblank(struct drm_device *dev, int crtc)
>> > +{
>> > +	;
>> > +}
>> > +
>> > +static const struct file_operations fsl_dcu_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		= no_llseek,
>> > +	.mmap		= drm_gem_cma_mmap,
>> > +};
>> > +
>> > +static struct drm_driver fsl_dcu_drm_driver = {
>> > +	.driver_features	= DRIVER_HAVE_IRQ | DRIVER_GEM | DRIVER_MODESET
>> > +				| DRIVER_PRIME,
>> > +	.load			= fsl_dcu_load,
>> > +	.unload			= fsl_dcu_unload,
>> > +	.preclose		= fsl_dcu_drm_preclose,
>> > +	.irq_handler		= fsl_dcu_drm_irq,
>> > +	.get_vblank_counter	= drm_vblank_count,
>> > +	.enable_vblank		= fsl_dcu_drm_enable_vblank,
>> > +	.disable_vblank		= fsl_dcu_drm_disable_vblank,
>> > +	.gem_free_object	= drm_gem_cma_free_object,
>> > +	.gem_vm_ops		= &drm_gem_cma_vm_ops,
>> > +	.prime_handle_to_fd	= drm_gem_prime_handle_to_fd,
>> > +	.prime_fd_to_handle	= drm_gem_prime_fd_to_handle,
>> > +	.gem_prime_import	= drm_gem_prime_import,
>> > +	.gem_prime_export	= drm_gem_prime_export,
>> > +	.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,
>> > +	.dumb_create		= drm_gem_cma_dumb_create,
>> > +	.dumb_map_offset	= drm_gem_cma_dumb_map_offset,
>> > +	.dumb_destroy		= drm_gem_dumb_destroy,
>> > +	.fops			= &fsl_dcu_drm_fops,
>> > +	.name			= "fsl-dcu-drm",
>> > +	.desc			= "Freescale DCU DRM",
>> > +	.date			= "20150213",
>> > +	.major			= 1,
>> > +	.minor			= 0,
>> > +};
>> > +
>> > +#ifdef CONFIG_PM_SLEEP
>> > +static int fsl_dcu_drm_pm_suspend(struct device *dev)
>> > +{
>> > +	struct fsl_dcu_drm_device *fsl_dev = dev_get_drvdata(dev);
>> > +
>> > +	if (of_device_is_compatible(fsl_dev->np, "fsl,ls1021a-dcu"))
>> > +		dcu_pixclk_disable();
>> > +
>> > +	drm_kms_helper_poll_disable(fsl_dev->ddev);
>> > +	fsl_dcu_drm_crtc_suspend(&fsl_dev->crtc);
>>
>> I get
>>
>> drivers/gpu/drm/fsl/fsl_dcu_drm_drv.c: In function
>> 'fsl_dcu_drm_pm_suspend':
>> drivers/gpu/drm/fsl/fsl_dcu_drm_drv.c:270:2: error: implicit declaration
>> of function 'fsl_dcu_drm_crtc_suspend'
>> [-Werror=implicit-function-declaration]
>>   fsl_dcu_drm_crtc_suspend(&fsl_dev->crtc);
>>   ^
>> drivers/gpu/drm/fsl/fsl_dcu_drm_drv.c: In function
>> 'fsl_dcu_drm_pm_resume':
>> drivers/gpu/drm/fsl/fsl_dcu_drm_drv.c:280:2: error: implicit declaration
>> of function 'fsl_dcu_drm_crtc_resume'
>> [-Werror=implicit-function-declaration]
>>   fsl_dcu_drm_crtc_resume(&fsl_dev->crtc);
>>   ^
>>
>> The function fsl_dcu_drm_crtc_suspend seems to be part of
>> fsl_dcu_drm_crtc.c, but is empty. While the other is missing
>> completely... Please fix/remove as appropriate.
>>
> 
> OK, I'll fix it
> 
> Regards
> Jianwei
>> > +
>> > +	return 0;
>> > +}
>> > +
>> > +static int fsl_dcu_drm_pm_resume(struct device *dev)
>> > +{
>> > +	struct fsl_dcu_drm_device *fsl_dev = dev_get_drvdata(dev);
>> > +
>> > +	drm_modeset_lock_all(fsl_dev->ddev);
>> > +	fsl_dcu_drm_crtc_resume(&fsl_dev->crtc);
>> > +	drm_modeset_unlock_all(fsl_dev->ddev);
>> > +	drm_kms_helper_poll_enable(fsl_dev->ddev);
>> > +
>> > +	if (of_device_is_compatible(fsl_dev->np, "fsl,ls1021a-dcu"))
>> > +		dcu_pixclk_enable();
>> > +
>> > +	return 0;
>> > +}
>> > +#endif
>> > +
>> > +static const struct dev_pm_ops fsl_dcu_drm_pm_ops = {
>> > +	SET_SYSTEM_SLEEP_PM_OPS(fsl_dcu_drm_pm_suspend,
>> fsl_dcu_drm_pm_resume)
>> > +};
>> > +
>> > +static int fsl_dcu_drm_probe(struct platform_device *pdev)
>> > +{
>> > +	return drm_platform_init(&fsl_dcu_drm_driver, pdev);
>> > +}
>> > +
>> > +static int fsl_dcu_drm_remove(struct platform_device *pdev)
>> > +{
>> > +	struct fsl_dcu_drm_device *fsl_dev = platform_get_drvdata(pdev);
>> > +
>> > +	drm_put_dev(fsl_dev->ddev);
>> > +
>> > +	return 0;
>> > +}
>> > +
>> > +static const struct of_device_id fsl_dcu_of_match[] = {
>> > +		{ .compatible = "fsl,ls1021a-dcu", },
>> > +		{ .compatible = "fsl,vf610-dcu", },
>> > +		{ },
>> > +};
>> > +MODULE_DEVICE_TABLE(of, fsl_dcu_of_match);
>> > +
>> > +static struct platform_driver fsl_dcu_drm_platform_driver = {
>> > +	.probe		= fsl_dcu_drm_probe,
>> > +	.remove		= fsl_dcu_drm_remove,
>> > +	.driver		= {
>> > +		.owner	= THIS_MODULE,
>> > +		.name	= "fsl,dcu",
>> > +		.pm	= &fsl_dcu_drm_pm_ops,
>> > +		.of_match_table = fsl_dcu_of_match,
>> > +	},
>> > +};
>> > +
>> > +module_platform_driver(fsl_dcu_drm_platform_driver);
>> > +
>> > +MODULE_ALIAS("platform:fsl-dcu-drm");
>> > +MODULE_DESCRIPTION("Freescale DCU DRM Driver");
>> > +MODULE_LICENSE("GPL");
>> > diff --git a/drivers/gpu/drm/fsl/fsl_dcu_drm_drv.h
>> > b/drivers/gpu/drm/fsl/fsl_dcu_drm_drv.h
>> > new file mode 100644
>> > index 0000000..27226109
>> > --- /dev/null
>> > +++ b/drivers/gpu/drm/fsl/fsl_dcu_drm_drv.h
>> > @@ -0,0 +1,210 @@
>> > +/*
>> > + * Copyright 2015 Freescale Semiconductor, Inc.
>> > + *
>> > + * Freescale DCU drm device driver
>> > + *
>> > + * 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 __FSL_DCU_DRM_DRV_H__
>> > +#define __FSL_DCU_DRM_DRV_H__
>> > +
>> > +#include <linux/kernel.h>
>> > +#include <linux/spinlock.h>
>> > +#include <stddef.h>
>> > +#include <drm/drm.h>
>> > +#include <drm/drmP.h>
>> > +#include <drm/drm_fb_helper.h>
>> > +#include <drm/drm_crtc_helper.h>
>> > +#include <drm/drm_gem_cma_helper.h>
>> > +#include <drm/drm_fb_cma_helper.h>
>> > +
>> > +#include "fsl_dcu_drm_crtc.h"
>> > +#include "fsl_dcu_drm_plane.h"
>> > +#include "fsl_dcu_drm_connector.h"
>> > +#define DRIVER_NAME			"fsl-dcu-drm"
>> > +
>> > +#define DCU_DCU_MODE			0x0010
>> > +#define DCU_MODE_BLEND_ITER(x)		((x) << 20)
>> > +#define DCU_MODE_RASTER_EN		BIT(14)
>> > +#define DCU_MODE_DCU_MODE(x)		(x)
>> > +#define DCU_MODE_DCU_MODE_MASK		0x03
>> > +#define DCU_MODE_OFF			0
>> > +#define DCU_MODE_NORMAL			1
>> > +#define DCU_MODE_TEST			2
>> > +#define DCU_MODE_COLORBAR		3
>> > +
>> > +#define DCU_BGND			0x0014
>> > +#define DCU_BGND_R(x)			((x) << 16)
>> > +#define DCU_BGND_G(x)			((x) << 8)
>> > +#define DCU_BGND_B(x)			(x)
>> > +
>> > +#define DCU_DISP_SIZE			0x0018
>> > +#define DCU_DISP_SIZE_DELTA_Y(x)	((x) << 16)
>> > +/*Regisiter value 1/16 of horizontal resolution*/
>> > +#define DCU_DISP_SIZE_DELTA_X(x)	((x) >> 4)
>> > +
>> > +#define DCU_HSYN_PARA			0x001c
>> > +#define DCU_HSYN_PARA_BP(x)		((x) << 22)
>> > +#define DCU_HSYN_PARA_PW(x)		((x) << 11)
>> > +#define DCU_HSYN_PARA_FP(x)		(x)
>> > +
>> > +#define DCU_VSYN_PARA			0x0020
>> > +#define DCU_VSYN_PARA_BP(x)		((x) << 22)
>> > +#define DCU_VSYN_PARA_PW(x)		((x) << 11)
>> > +#define DCU_VSYN_PARA_FP(x)		(x)
>> > +
>> > +#define DCU_SYN_POL			0x0024
>> > +#define DCU_SYN_POL_INV_PXCK_FALL	(0 << 6)
>> > +#define DCU_SYN_POL_NEG_REMAIN		(0 << 5)
>> > +#define DCU_SYN_POL_INV_VS_LOW		BIT(1)
>> > +#define DCU_SYN_POL_INV_HS_LOW		BIT(0)
>> > +
>> > +#define DCU_THRESHOLD			0x0028
>> > +#define DCU_THRESHOLD_LS_BF_VS(x)	((x) << 16)
>> > +#define DCU_THRESHOLD_OUT_BUF_HIGH(x)	((x) << 8)
>> > +#define DCU_THRESHOLD_OUT_BUF_LOW(x)	(x)
>> > +#define BF_VS_VAL			0x03
>> > +#define BUF_MAX_VAL			0x78
>> > +#define BUF_MIN_VAL			0x0a
>> > +
>> > +#define DCU_INT_STATUS			0x002C
>> > +#define DCU_INT_STATUS_VSYNC		BIT(0)
>> > +#define DCU_INT_STATUS_UNDRUN		BIT(1)
>> > +#define DCU_INT_STATUS_LSBFVS		BIT(2)
>> > +#define DCU_INT_STATUS_VBLANK		BIT(3)
>> > +#define DCU_INT_STATUS_CRCREADY		BIT(4)
>> > +#define DCU_INT_STATUS_CRCOVERFLOW	BIT(5)
>> > +#define DCU_INT_STATUS_P1FIFOLO		BIT(6)
>> > +#define DCU_INT_STATUS_P1FIFOHI		BIT(7)
>> > +#define DCU_INT_STATUS_P2FIFOLO		BIT(8)
>> > +#define DCU_INT_STATUS_P2FIFOHI		BIT(9)
>> > +#define DCU_INT_STATUS_PROGEND		BIT(10)
>> > +#define DCU_INT_STATUS_IPMERROR		BIT(11)
>> > +#define DCU_INT_STATUS_LYRTRANS		BIT(12)
>> > +#define DCU_INT_STATUS_DMATRANS		BIT(14)
>> > +#define DCU_INT_STATUS_P3FIFOLO		BIT(16)
>> > +#define DCU_INT_STATUS_P3FIFOHI		BIT(17)
>> > +#define DCU_INT_STATUS_P4FIFOLO		BIT(18)
>> > +#define DCU_INT_STATUS_P4FIFOHI		BIT(19)
>> > +#define DCU_INT_STATUS_P1EMPTY		BIT(26)
>> > +#define DCU_INT_STATUS_P2EMPTY		BIT(27)
>> > +#define DCU_INT_STATUS_P3EMPTY		BIT(28)
>> > +#define DCU_INT_STATUS_P4EMPTY		BIT(29)
>> > +
>> > +#define DCU_INT_MASK			0x0030
>> > +#define DCU_INT_MASK_VSYNC		BIT(0)
>> > +#define DCU_INT_MASK_UNDRUN		BIT(1)
>> > +#define DCU_INT_MASK_LSBFVS		BIT(2)
>> > +#define DCU_INT_MASK_VBLANK		BIT(3)
>> > +#define DCU_INT_MASK_CRCREADY		BIT(4)
>> > +#define DCU_INT_MASK_CRCOVERFLOW	BIT(5)
>> > +#define DCU_INT_MASK_P1FIFOLO		BIT(6)
>> > +#define DCU_INT_MASK_P1FIFOHI		BIT(7)
>> > +#define DCU_INT_MASK_P2FIFOLO		BIT(8)
>> > +#define DCU_INT_MASK_P2FIFOHI		BIT(9)
>> > +#define DCU_INT_MASK_PROGEND		BIT(10)
>> > +#define DCU_INT_MASK_IPMERROR		BIT(11)
>> > +#define DCU_INT_MASK_LYRTRANS		BIT(12)
>> > +#define DCU_INT_MASK_DMATRANS		BIT(14)
>> > +#define DCU_INT_MASK_P3FIFOLO		BIT(16)
>> > +#define DCU_INT_MASK_P3FIFOHI		BIT(17)
>> > +#define DCU_INT_MASK_P4FIFOLO		BIT(18)
>> > +#define DCU_INT_MASK_P4FIFOHI		BIT(19)
>> > +#define DCU_INT_MASK_P1EMPTY		BIT(26)
>> > +#define DCU_INT_MASK_P2EMPTY		BIT(27)
>> > +#define DCU_INT_MASK_P3EMPTY		BIT(28)
>> > +#define DCU_INT_MASK_P4EMPTY		BIT(29)
>> > +
>> > +#define DCU_DIV_RATIO			0x0054
>> > +
>> > +#define DCU_UPDATE_MODE			0x00cc
>> > +#define DCU_UPDATE_MODE_MODE		BIT(31)
>> > +#define DCU_UPDATE_MODE_READREG		BIT(30)
>> > +
>> > +#define DCU_DCFB_MAX			0x300
>> > +
>> > +#define DCU_CTRLDESCLN_1(x)		(0x200 + (x) * 0x40)
>> > +#define DCU_CTRLDESCLN_1_HEIGHT(x)	((x) << 16)
>> > +#define DCU_CTRLDESCLN_1_WIDTH(x)	(x)
>> > +
>> > +#define DCU_CTRLDESCLN_2(x)		(0x204 + (x) * 0x40)
>> > +#define DCU_CTRLDESCLN_2_POSY(x)	((x) << 16)
>> > +#define DCU_CTRLDESCLN_2_POSX(x)	(x)
>> > +
>> > +#define DCU_CTRLDESCLN_3(x)		(0x208 + (x) * 0x40)
>> > +
>> > +#define DCU_CTRLDESCLN_4(x)		(0x20c + (x) * 0x40)
>> > +#define DCU_CTRLDESCLN_4_EN		BIT(31)
>> > +#define DCU_CTRLDESCLN_4_TILE_EN	BIT(30)
>> > +#define DCU_CTRLDESCLN_4_DATA_SEL_CLUT	BIT(29)
>> > +#define DCU_CTRLDESCLN_4_SAFETY_EN	BIT(28)
>> > +#define DCU_CTRLDESCLN_4_TRANS(x)	((x) << 20)
>> > +#define DCU_CTRLDESCLN_4_BPP(x)		((x) << 16)
>> > +#define DCU_CTRLDESCLN_4_RLE_EN		BIT(15)
>> > +#define DCU_CTRLDESCLN_4_LUOFFS(x)	((x) << 4)
>> > +#define DCU_CTRLDESCLN_4_BB_ON		BIT(2)
>> > +#define DCU_CTRLDESCLN_4_AB(x)		(x)
>> > +
>> > +#define DCU_CTRLDESCLN_5(x)		(0x210 + (x) * 0x40)
>> > +#define DCU_CTRLDESCLN_5_CKMAX_R(x)	((x) << 16)
>> > +#define DCU_CTRLDESCLN_5_CKMAX_G(x)	((x) << 8)
>> > +#define DCU_CTRLDESCLN_5_CKMAX_B(x)	(x)
>> > +
>> > +#define DCU_CTRLDESCLN_6(x)		(0x214 + (x) * 0x40)
>> > +#define DCU_CTRLDESCLN_6_CKMIN_R(x)	((x) << 16)
>> > +#define DCU_CTRLDESCLN_6_CKMIN_G(x)	((x) << 8)
>> > +#define DCU_CTRLDESCLN_6_CKMIN_B(x)	(x)
>> > +
>> > +#define DCU_CTRLDESCLN_7(x)		(0x218 + (x) * 0x40)
>> > +#define DCU_CTRLDESCLN_7_TILE_VER(x)	((x) << 16)
>> > +#define DCU_CTRLDESCLN_7_TILE_HOR(x)	(x)
>> > +
>> > +#define DCU_CTRLDESCLN_8(x)		(0x21c + (x) * 0x40)
>> > +#define DCU_CTRLDESCLN_8_FG_FCOLOR(x)	(x)
>> > +
>> > +#define DCU_CTRLDESCLN_9(x)		(0x220 + (x) * 0x40)
>> > +#define DCU_CTRLDESCLN_9_BG_BCOLOR(x)	(x)
>> > +
>> > +#define DCU_CTRLDESCLN_10(x)		(0x224 + (x) * 0x40)
>> > +#define DCU_CTRLDESCLN_10_POST_SKIP(x)	((x) << 16)
>> > +#define DCU_CTRLDESCLN_10_PRE_SKIP(x)	(x)
>> > +
>> > +#define FSL_DCU_RGB565			4
>> > +#define FSL_DCU_RGB888			5
>> > +#define FSL_DCU_ARGB8888		6
>> > +#define FSL_DCU_ARGB1555		11
>> > +#define FSL_DCU_ARGB4444		12
>> > +#define FSL_DCU_YUV422			14
>> > +
>> > +#define TCON_CTRL1			0x0000
>> > +#define TCON_BYPASS_ENABLE		BIT(29)
>> > +
>> > +#define DBG(fmt, ...) DRM_DEBUG(fmt"\n", ##__VA_ARGS__)
>> > +
>> > +struct clk;
>> > +struct device;
>> > +struct drm_device;
>> > +
>> > +struct fsl_dcu_drm_device {
>> > +	struct device *dev;
>> > +	struct device_node *np;
>> > +	struct regmap *regmap;
>> > +	struct regmap *tcon_regmap;
>> > +	unsigned int irq;
>> > +	struct clk *clk;
>> > +	/*protects hardware register*/
>> > +	spinlock_t irq_lock;
>> > +	struct drm_device *ddev;
>> > +	struct drm_fbdev_cma *fbdev;
>> > +	struct fsl_dcu_drm_crtc crtc;
>> > +	struct drm_encoder encoder;
>> > +	struct fsl_dcu_drm_connector connector;
>> > +};
>> > +
>> > +void fsl_dcu_fbdev_init(struct drm_device *dev);
>> > +
>> > +#endif /* __FSL_DCU_DRM_DRV_H__ */
>> > diff --git a/drivers/gpu/drm/fsl/fsl_dcu_drm_fbdev.c
>> > b/drivers/gpu/drm/fsl/fsl_dcu_drm_fbdev.c
>> > new file mode 100644
>> > index 0000000..f8ef0e1
>> > --- /dev/null
>> > +++ b/drivers/gpu/drm/fsl/fsl_dcu_drm_fbdev.c
>> > @@ -0,0 +1,26 @@
>> > +/*
>> > + * Copyright 2015 Freescale Semiconductor, Inc.
>> > + *
>> > + * 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.
>> > + *
>> > + * This program is distributed in the hope that it will be useful, but
>> WITHOUT
>> > + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
>> or
>> > + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
>> License for
>> > + * more details.
>> > + *
>> > + */
>> > +
>> > +#include <drm/drmP.h>
>> > +#include <drm/drm_fb_cma_helper.h>
>> > +
>> > +#include "fsl_dcu_drm_drv.h"
>> > +
>> > +/* initialize fbdev helper */
>> > +void fsl_dcu_fbdev_init(struct drm_device *dev)
>> > +{
>> > +	struct fsl_dcu_drm_device *fsl_dev = dev_get_drvdata(dev->dev);
>> > +
>> > +	fsl_dev->fbdev = drm_fbdev_cma_init(dev, 24, 1, 1);
>> > +}
>> > diff --git a/drivers/gpu/drm/fsl/fsl_dcu_drm_kms.c
>> > b/drivers/gpu/drm/fsl/fsl_dcu_drm_kms.c
>> > new file mode 100644
>> > index 0000000..0de21c6
>> > --- /dev/null
>> > +++ b/drivers/gpu/drm/fsl/fsl_dcu_drm_kms.c
>> > @@ -0,0 +1,42 @@
>> > +/*
>> > + * Copyright 2015 Freescale Semiconductor, Inc.
>> > + *
>> > + * Freescale DCU drm device driver
>> > + *
>> > + * 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 "fsl_dcu_drm_crtc.h"
>> > +#include "fsl_dcu_drm_connector.h"
>> > +#include "fsl_dcu_drm_drv.h"
>> > +
>> > +static const struct drm_mode_config_funcs fsl_dcu_drm_mode_config_funcs
>> = {
>> > +	.fb_create = drm_fb_cma_create,
>> > +	.atomic_check = drm_atomic_helper_check,
>> > +	.atomic_commit = drm_atomic_helper_commit,
>> > +};
>> > +
>> > +int fsl_dcu_drm_modeset_init(struct fsl_dcu_drm_device *fsl_dev)
>> > +{
>> > +	drm_mode_config_init(fsl_dev->ddev);
>> > +
>> > +	fsl_dev->ddev->mode_config.min_width = 0;
>> > +	fsl_dev->ddev->mode_config.min_height = 0;
>> > +	fsl_dev->ddev->mode_config.max_width = 2031;
>> > +	fsl_dev->ddev->mode_config.max_height = 2047;
>> > +	fsl_dev->ddev->mode_config.funcs = &fsl_dcu_drm_mode_config_funcs;
>> > +
>> > +	drm_kms_helper_poll_init(fsl_dev->ddev);
>> > +	fsl_dcu_drm_crtc_create(fsl_dev);
>> > +	fsl_dcu_drm_encoder_create(fsl_dev, &fsl_dev->crtc);
>> > +	fsl_dcu_drm_connector_create(fsl_dev, &fsl_dev->encoder);
>> > +	drm_mode_config_reset(fsl_dev->ddev);
>> > +
>> > +	return 0;
>> > +}
>> > diff --git a/drivers/gpu/drm/fsl/fsl_dcu_drm_kms.h
>> > b/drivers/gpu/drm/fsl/fsl_dcu_drm_kms.h
>> > new file mode 100644
>> > index 0000000..b9bd299
>> > --- /dev/null
>> > +++ b/drivers/gpu/drm/fsl/fsl_dcu_drm_kms.h
>> > @@ -0,0 +1,17 @@
>> > +/*
>> > + * Copyright 2015 Freescale Semiconductor, Inc.
>> > + *
>> > + * Freescale DCU drm device driver
>> > + *
>> > + * 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 __FSL_DCU_DRM_KMS_H__
>> > +#define __FSL_DCU_DRM_KMS_H__
>> > +
>> > +int fsl_dcu_drm_modeset_init(struct fsl_dcu_drm_device *fsl_dev);
>> > +
>> > +#endif /* __FSL_DCU_DRM_KMS_H__ */
>> > diff --git a/drivers/gpu/drm/fsl/fsl_dcu_drm_plane.c
>> > b/drivers/gpu/drm/fsl/fsl_dcu_drm_plane.c
>> > new file mode 100644
>> > index 0000000..6146e80
>> > --- /dev/null
>> > +++ b/drivers/gpu/drm/fsl/fsl_dcu_drm_plane.c
>> > @@ -0,0 +1,192 @@
>> > +/*
>> > + * Copyright 2015 Freescale Semiconductor, Inc.
>> > + *
>> > + * Freescale DCU drm device driver
>> > + *
>> > + * 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_crtc.h>
>> > +#include <drm/drm_crtc_helper.h>
>> > +#include <drm/drm_fb_cma_helper.h>
>> > +#include <drm/drm_gem_cma_helper.h>
>> > +#include <linux/regmap.h>
>> > +#include <drm/drm_plane_helper.h>
>> > +#include <drm/drm_atomic_helper.h>
>> > +
>> > +#include "fsl_dcu_drm_drv.h"
>> > +#include "fsl_dcu_drm_kms.h"
>> > +#include "fsl_dcu_drm_plane.h"
>> > +
>> > +#define to_fsl_dcu_plane(plane) \
>> > +	container_of(plane, struct fsl_dcu_drm_plane, plane)
>> > +
>> > +static int
>> > +fsl_dcu_drm_plane_prepare_fb(struct drm_plane *plane,
>> > +			     struct drm_framebuffer *fb,
>> > +			     const struct drm_plane_state *new_state)
>> > +{
>> > +	return 0;
>> > +}
>> > +
>> > +static void
>> > +fsl_dcu_drm_plane_cleanup_fb(struct drm_plane *plane,
>> > +			     struct drm_framebuffer *fb,
>> > +			     const struct drm_plane_state *new_state)
>> > +{
>> > +}
>> > +
>> > +static int fsl_dcu_drm_plane_atomic_check(struct drm_plane *plane,
>> > +					  struct drm_plane_state *state)
>> > +{
>> > +	return 0;
>> > +}
>> > +
>> > +static void fsl_dcu_drm_plane_atomic_disable(struct drm_plane *plane,
>> > +					     struct drm_plane_state *old_state)
>> > +{
>> > +}
>> > +
>> > +void fsl_dcu_drm_plane_atomic_update(struct drm_plane *plane,
>> > +				     struct drm_plane_state *old_state)
>> > +{
>> > +	struct fsl_dcu_drm_device *fsl_dev = plane->dev->dev_private;
>> > +	struct drm_plane_state *state = plane->state;
>> > +	struct drm_framebuffer *fb = plane->state->fb;
>> > +	u32 index, alpha, bpp;
>> > +	struct drm_gem_cma_object *gem;
>> > +	struct fsl_dcu_drm_plane *fsl_plane = to_fsl_dcu_plane(plane);
>> > +
>> > +	index = fsl_plane->index;
>> > +	gem = drm_fb_cma_get_gem_obj(fb, 0);
>> > +
>> > +	switch (fb->pixel_format) {
>> > +	case DRM_FORMAT_RGB565:
>> > +		bpp = FSL_DCU_RGB565;
>> > +		alpha = 0xff;
>> > +		break;
>> > +	case DRM_FORMAT_RGB888:
>> > +		bpp = FSL_DCU_RGB888;
>> > +		alpha = 0xff;
>> > +		break;
>> > +	case DRM_FORMAT_ARGB8888:
>> > +		bpp = FSL_DCU_ARGB8888;
>> > +		alpha = 0xff;
>> > +		break;
>> > +	case DRM_FORMAT_BGRA4444:
>> > +		bpp = FSL_DCU_ARGB4444;
>> > +		alpha = 0xff;
>> > +		break;
>> > +	case DRM_FORMAT_ARGB1555:
>> > +		bpp = FSL_DCU_ARGB1555;
>> > +		alpha = 0xff;
>> > +		break;
>> > +	case DRM_FORMAT_YUV422:
>> > +		bpp = FSL_DCU_YUV422;
>> > +		alpha = 0xff;
>> > +		break;
>> > +	default:
>> > +		return;
>> > +	}
>> > +
>> > +	regmap_write(fsl_dev->regmap, DCU_CTRLDESCLN_1(index),
>> > +		     DCU_CTRLDESCLN_1_HEIGHT(state->crtc_h) |
>> > +		     DCU_CTRLDESCLN_1_WIDTH(state->crtc_w));
>> > +	regmap_write(fsl_dev->regmap, DCU_CTRLDESCLN_2(index),
>> > +		     DCU_CTRLDESCLN_2_POSY(state->crtc_y) |
>> > +		     DCU_CTRLDESCLN_2_POSX(state->crtc_x));
>> > +	regmap_write(fsl_dev->regmap, DCU_CTRLDESCLN_3(index), gem->paddr);
>> > +	regmap_write(fsl_dev->regmap, DCU_CTRLDESCLN_4(index),
>> > +		     DCU_CTRLDESCLN_4_EN |
>> > +		     DCU_CTRLDESCLN_4_TRANS(alpha) |
>> > +		     DCU_CTRLDESCLN_4_BPP(bpp) |
>> > +		     DCU_CTRLDESCLN_4_AB(0));
>> > +	regmap_write(fsl_dev->regmap, DCU_CTRLDESCLN_5(index),
>> > +		     DCU_CTRLDESCLN_5_CKMAX_R(0xFF) |
>> > +		     DCU_CTRLDESCLN_5_CKMAX_G(0xFF) |
>> > +		     DCU_CTRLDESCLN_5_CKMAX_B(0xFF));
>> > +	regmap_write(fsl_dev->regmap, DCU_CTRLDESCLN_6(index),
>> > +		     DCU_CTRLDESCLN_6_CKMIN_R(0) |
>> > +		     DCU_CTRLDESCLN_6_CKMIN_G(0) |
>> > +		     DCU_CTRLDESCLN_6_CKMIN_B(0));
>> > +	regmap_write(fsl_dev->regmap, DCU_CTRLDESCLN_7(index), 0);
>> > +	regmap_write(fsl_dev->regmap, DCU_CTRLDESCLN_8(index),
>> > +		     DCU_CTRLDESCLN_8_FG_FCOLOR(0));
>> > +	regmap_write(fsl_dev->regmap, DCU_CTRLDESCLN_9(index),
>> > +		     DCU_CTRLDESCLN_9_BG_BCOLOR(0));
>> > +	if (of_device_is_compatible(fsl_dev->np, "fsl,ls1021a-dcu"))
>> > +		regmap_write(fsl_dev->regmap, DCU_CTRLDESCLN_10(index),
>> > +			     DCU_CTRLDESCLN_10_POST_SKIP(0) |
>> > +			     DCU_CTRLDESCLN_10_PRE_SKIP(0));
>> > +	regmap_update_bits(fsl_dev->regmap, DCU_DCU_MODE,
>> > +			   DCU_MODE_DCU_MODE_MASK,
>> > +			   DCU_MODE_DCU_MODE(DCU_MODE_NORMAL));
>> > +	regmap_write(fsl_dev->regmap, DCU_UPDATE_MODE,
>> DCU_UPDATE_MODE_READREG);
>> > +}
>> > +
>> > +int fsl_dcu_drm_plane_disable(struct drm_plane *plane)
>> > +{
>> > +	return 0;
>> > +}
>> > +
>> > +void fsl_dcu_drm_plane_destroy(struct drm_plane *plane)
>> > +{
>> > +	fsl_dcu_drm_plane_disable(plane);
>> > +	drm_plane_cleanup(plane);
>> > +}
>> > +
>> > +static const uint32_t fsl_dcu_drm_plane_formats[] = {
>> > +	DRM_FORMAT_RGB565,
>> > +	DRM_FORMAT_RGB888,
>> > +	DRM_FORMAT_ARGB8888,
>> > +	DRM_FORMAT_ARGB4444,
>> > +	DRM_FORMAT_ARGB1555,
>> > +	DRM_FORMAT_YUV422,
>> > +};
>> > +
>> > +static const struct drm_plane_funcs fsl_dcu_drm_plane_funcs = {
>> > +	.update_plane = drm_atomic_helper_update_plane,
>> > +	.disable_plane = drm_atomic_helper_disable_plane,
>> > +	.destroy = fsl_dcu_drm_plane_destroy,
>> > +	.atomic_duplicate_state = drm_atomic_helper_plane_duplicate_state,
>> > +	.atomic_destroy_state = drm_atomic_helper_plane_destroy_state,
>> > +	.reset = drm_atomic_helper_plane_reset,
>> > +};
>> > +
>> > +static const struct drm_plane_helper_funcs
>> fsl_dcu_drm_plane_helper_funcs = {
>> > +	.prepare_fb = fsl_dcu_drm_plane_prepare_fb,
>> > +	.cleanup_fb = fsl_dcu_drm_plane_cleanup_fb,
>> > +	.atomic_check = fsl_dcu_drm_plane_atomic_check,
>> > +	.atomic_update = fsl_dcu_drm_plane_atomic_update,
>> > +	.atomic_disable = fsl_dcu_drm_plane_atomic_disable,
>> > +};
>> > +
>> > +struct drm_plane *fsl_dcu_drm_primary_create_plane(struct drm_device
>> *dev)
>> > +{
>> > +	struct drm_plane *primary;
>> > +	int ret;
>> > +
>> > +	primary = kzalloc(sizeof(*primary), GFP_KERNEL);
>> > +	if (!primary) {
>> > +		DRM_DEBUG_KMS("Failed to allocate primary plane\n");
>> > +		return NULL;
>> > +	}
>> > +
>> > +	/* possible_crtc's will be filled in later by crtc_init */
>> > +	ret = drm_universal_plane_init(dev, primary, 0,
>> > +				       &fsl_dcu_drm_plane_funcs,
>> > +				       fsl_dcu_drm_plane_formats,
>> > +				       ARRAY_SIZE(fsl_dcu_drm_plane_formats),
>> > +				       DRM_PLANE_TYPE_PRIMARY);
>> > +	if (ret) {
>> > +		kfree(primary);
>> > +		primary = NULL;
>> > +	}
>> > +	drm_plane_helper_add(primary, &fsl_dcu_drm_plane_helper_funcs);
>> > +
>> > +	return primary;
>> > +}
>> > diff --git a/drivers/gpu/drm/fsl/fsl_dcu_drm_plane.h
>> > b/drivers/gpu/drm/fsl/fsl_dcu_drm_plane.h
>> > new file mode 100644
>> > index 0000000..ccbfa61
>> > --- /dev/null
>> > +++ b/drivers/gpu/drm/fsl/fsl_dcu_drm_plane.h
>> > @@ -0,0 +1,23 @@
>> > +/*
>> > + * Copyright 2015 Freescale Semiconductor, Inc.
>> > + *
>> > + * Freescale DCU drm device driver
>> > + *
>> > + * 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 __FSL_DCU_DRM_PLANE_H__
>> > +#define __FSL_DCU_DRM_PLANE_H__
>> > +
>> > +struct fsl_dcu_drm_device;
>> > +struct fsl_dcu_drm_plane {
>> > +	struct drm_plane plane;
>> > +	unsigned int index;
>> > +};
>> > +
>> > +struct drm_plane *fsl_dcu_drm_primary_create_plane(struct drm_device
>> *dev);
>> > +
>> > +#endif /* __FSL_DCU_DRM_PLANE_H__ */

--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Jianwei.Wang@freescale.com April 8, 2015, 7:17 a.m. UTC | #4
Hi Stefan,

> -----Original Message-----
> From: Stefan Agner [mailto:stefan@agner.ch]
> Sent: Tuesday, April 07, 2015 8:12 PM
> To: Wang Jianwei-B52261
> Cc: Wood Scott-B07421; airlied@linux.ie; dri-devel@lists.freedesktop.org;
> devicetree@vger.kernel.org; Xiubo Li; Wang Huan-B18965; linux-
> kernel@vger.kernel.org; Jin Zhengxiong-R64188; linux-arm-
> kernel@lists.infradead.org
> Subject: RE: [PATCH v3 1/4] drm/layerscape: Add Freescale DCU DRM driver
> 
> Hi Jianwei,
> 
> On 2015-04-07 08:44, Jianwei.Wang@freescale.com wrote:
> > Hi Stefan,
> >
> > Thank you for your review and testing on Vybrid F610 device. This driver
> > just implement the basic functions and it only support the exported
> > framebuffer access. Some DRM interfaces are not implemented now. So your
> > test result is normal. I will implement these interfaces with patches
> soon
> > afterwards. I don't plan to add new features for the initial version
> driver,
> > otherwise it will be a long term for this version.
> >
> > I tested on ls1021a using TFT panel, there are no flickers on the screen
> > when inserting a USB HID device. I will do more test if time permits.
> >
> > By the way, could please give me some guidance on how X-Server use DRM
> > Interface directly? Do you have some papers or webpage about this?
> 
> I'm using the modesetting X.org driver. Lots of distributions ship that
> driver as a package (e.g. xserver-xorg-video-modesetting in Debian, or
> xf86-video-modesetting in OpenEmbedded). Since 1.17 this driver has even
> been included into the main source tree of Xorg X-Server
> (http://cgit.freedesktop.org/xorg/xserver/tree/hw/xfree86/drivers/modesett
> ing)
> 
> This driver is using KMS/DRM interface and should work well for
> un-accelerated graphic devices. This is a a much nicer way to use X.org
> on top of a DRM driver, since it avoids going through the legacy fbdev
> interface. The man page shows how to use it:
> http://linux.die.net/man/4/modesetting
> 
> So, when the driver is installed, it is just choosing that driver in
> xorg.conf:
> 
> Section "Device"
>         Identifier      "dcu"
>         Driver          "modesetting"
> EndSection
> 

Thank you for your guidance.

> Some more comments below...
> 
> >
> > My reply below...
> >
> >>
> >> Hi Jianwei,
> >>
> >> The driver worked on a Vybrid VF610 device using the exported
> >> framebuffer. However, when using X-Server through the DRM interface
> >> directly (by using the modesetting driver) I get just a black screen so
> >> far, still investigating the reason. What user-space interfaces did you
> >> test?
> >>
> >> When using the FB device and insert a USB HID device, I get some
> >> flickers on the screen. I didn't had those on the dcufb driver, did you
> >> notice something like this too? Probably related to the resolution, I'm
> >> using VGA resolution.
> >>
> >> Some comments below.
> >>
> >>
> >> On 2015-03-26 06:37, Jianwei Wang wrote:
> >> > This patch add support for Two Dimensional Animation and Compositing
> >> > Engine (2D-ACE) on the Freescale SoCs.
> >> >
> >> > 2D-ACE is a Freescale display controller. 2D-ACE describes
> >> > the functionality of the module extremely well its name is a value
> >> > that cannot be used as a token in programming languages.
> >> > Instead the valid token "DCU" is used to tag the register names and
> >> > function names.
> >> >
> >> > The Display Controller Unit (DCU) module is a system master that
> >> > fetches graphics stored in internal or external memory and displays
> >> > them on a TFT LCD panel. A wide range of panel sizes is supported
> >> > and the timing of the interface signals is highly configurable.
> >> > Graphics are read directly from memory and then blended in real-time,
> >> > which allows for dynamic content creation with minimal CPU
> >> > intervention.
> >> >
> >> > The features:
> >> > (1) Full RGB888 output to TFT LCD panel.
> >> > (2) For the current LCD panel, WQVGA "480x272" is supported.
> >> > (3) Blending of each pixel using up to 4 source layers
> >> > dependent on size of panel.
> >>
> >> modetest only shows one layer currently...
> >
> > Yes, only one plane and one framebuffer were created now, others
> > maybe create as user requirement or create all when initializing,
> > I'm not sure now. This describe the hardware feature
> >
> >>
> >> > (4) Each graphic layer can be placed with one pixel resolution
> >> > in either axis.
> >> > (5) Each graphic layer support RGB565 and RGB888 direct colors
> >> > without alpha channel
> >> > and BGRA8888 direct colors with an alpha channel.
> >>
> >> The array fsl_dcu_drm_plane_formats below shows more formats, does this
> >> commit log needs updating?
> >>
> >
> > I agree with your suggestion, I will update this commit log
> >
> >> > (6) Each graphic layer support alpha blending with 8-bit
> >> > resolution.
> >> >
> >> > This is a simplified version, only one primary plane, one
> >> > framebuffer created for fbdev, one crtc, one connector for
> >> > TFT LCD panel, an encoder.
> >> >
> >> > Signed-off-by: Alison Wang <b18965@freescale.com>
> >> > Signed-off-by: Xiubo Li <lixiubo@cmss.chinamobile.com>
> >> > Signed-off-by: Jianwei Wang <b52261@freescale.com>
> >> > ---
> >> >
> >> > Changed in V3:
> >> >
> >> > - Test driver on Vybrid board and add compatible string
> >> > - Remove unused functions
> >> > - set default crtc for encoder
> >> > - replace legacy functions with atomic help functions
> >> > - Set the unique name of the DRM device
> >> > - Implement irq handle function for vblank interrupt
> >> >
> >> > Changed in v2:
> >> > - Add atomic support
> >> > - Modify bindings file
> >> > - Rename node for compatibility
> >> > - Move platform related code out for compatibility
> >> >
> >> >  .../devicetree/bindings/drm/fsl/fsl,dcu.txt        |  50 ++++
> >> >  drivers/gpu/drm/Kconfig                            |   2 +
> >> >  drivers/gpu/drm/Makefile                           |   1 +
> >> >  drivers/gpu/drm/fsl/Kconfig                        |  17 ++
> >> >  drivers/gpu/drm/fsl/Makefile                       |   8 +
> >> >  drivers/gpu/drm/fsl/fsl_dcu_drm_connector.c        | 193
> ++++++++++++
> >> >  drivers/gpu/drm/fsl/fsl_dcu_drm_connector.h        |  30 ++
> >> >  drivers/gpu/drm/fsl/fsl_dcu_drm_crtc.c             | 165 ++++++++++
> >> >  drivers/gpu/drm/fsl/fsl_dcu_drm_crtc.h             |  26 ++
> >> >  drivers/gpu/drm/fsl/fsl_dcu_drm_drv.c              | 331
> >> +++++++++++++++++++++
> >> >  drivers/gpu/drm/fsl/fsl_dcu_drm_drv.h              | 210
> +++++++++++++
> >> >  drivers/gpu/drm/fsl/fsl_dcu_drm_fbdev.c            |  26 ++
> >> >  drivers/gpu/drm/fsl/fsl_dcu_drm_kms.c              |  42 +++
> >> >  drivers/gpu/drm/fsl/fsl_dcu_drm_kms.h              |  17 ++
> >> >  drivers/gpu/drm/fsl/fsl_dcu_drm_plane.c            | 192
> ++++++++++++
> >> >  drivers/gpu/drm/fsl/fsl_dcu_drm_plane.h            |  23 ++
> >> >  16 files changed, 1333 insertions(+)
> >> >  create mode 100644
> >> Documentation/devicetree/bindings/drm/fsl/fsl,dcu.txt
> >> >  create mode 100644 drivers/gpu/drm/fsl/Kconfig
> >> >  create mode 100644 drivers/gpu/drm/fsl/Makefile
> >> >  create mode 100644 drivers/gpu/drm/fsl/fsl_dcu_drm_connector.c
> >> >  create mode 100644 drivers/gpu/drm/fsl/fsl_dcu_drm_connector.h
> >> >  create mode 100644 drivers/gpu/drm/fsl/fsl_dcu_drm_crtc.c
> >> >  create mode 100644 drivers/gpu/drm/fsl/fsl_dcu_drm_crtc.h
> >> >  create mode 100644 drivers/gpu/drm/fsl/fsl_dcu_drm_drv.c
> >> >  create mode 100644 drivers/gpu/drm/fsl/fsl_dcu_drm_drv.h
> >> >  create mode 100644 drivers/gpu/drm/fsl/fsl_dcu_drm_fbdev.c
> >> >  create mode 100644 drivers/gpu/drm/fsl/fsl_dcu_drm_kms.c
> >> >  create mode 100644 drivers/gpu/drm/fsl/fsl_dcu_drm_kms.h
> >> >  create mode 100644 drivers/gpu/drm/fsl/fsl_dcu_drm_plane.c
> >> >  create mode 100644 drivers/gpu/drm/fsl/fsl_dcu_drm_plane.h
> >> >
> >> > diff --git a/Documentation/devicetree/bindings/drm/fsl/fsl,dcu.txt
> >> > b/Documentation/devicetree/bindings/drm/fsl/fsl,dcu.txt
> >> > new file mode 100644
> >> > index 0000000..bdc7d5b
> >> > --- /dev/null
> >> > +++ b/Documentation/devicetree/bindings/drm/fsl/fsl,dcu.txt
> >> > @@ -0,0 +1,50 @@
> >> > +Device Tree bindings for Freescale DCU DRM Driver
> >> > +
> >> > +Required properties:
> >> > +- compatible:           Should be one of
> >> > +	* "fsl,ls1021a-dcu".
> >> > +	* "fsl,vf610-dcu".
> >>
> >> In the Vybrid reference manual, that IP is denoted as "DCU4". Any
> reason
> >> why you left out the DCU version? Is this different for LS1021a? On the
> >> other hand, with the SoC in the name, the IP should be specified clear
> >> enough.
> >>
> >
> > In the LS1021A reference manual, no DCU version related words. I asked
> > previous DCU owner, she told me that LS1021A use DCU5 and she also point
> > out that the same DCU version there may be differences between different
> > SoCs. So I named compatible string with SoC name.
> 
> Ok, I'm fine with that, thx for the background information.
> 
> >
> >> > +- reg:                  Address and length of the register set for
> dcu.
> >> > +- clocks:               From common clock binding: handle to dcu
> clock.
> >> > +- clock-names:          From common clock binding: Shall be "dcu".
> >> > +- display:              The phandle to display node.
> >> > +
> >> > +Required properties:
> >> > +- bits-per-pixel:       <16> for RGB565,
> >> > +			<24> for RGB888,
> >> > +			<32> for RGB8888.
> >> > +
> >> > +Required timing node for dispplay sub-node:
> >> > +- display-timings:      Refer to binding doc display-timing.txt for
> >> details.
> >> > +
> >> > +Examples:
> >> > +dcu: dcu@2ce0000 {
> >> > +	compatible = "fsl,ls1021a-dcu";
> >> > +	reg = <0x0 0x2ce0000 0x0 0x10000>;
> >> > +	clocks = <&platform_clk 0>;
> >> > +	clock-names = "dcu";
> >> > +	big-endian;
> >> > +	display = <&display>;
> >> > +
> >> > +	display: display@0 {
> >> > +		bits-per-pixel = <24>;
> >> > +
> >> > +		display-timings {
> >> > +			native-mode = <&timing0>;
> >> > +			timing0: nl4827hc19 {
> >> > +				clock-frequency = <10870000>;
> >> > +				hactive = <480>;
> >> > +				vactive = <272>;
> >> > +				hback-porch = <2>;
> >> > +				hfront-porch = <2>;
> >> > +				vback-porch = <1>;
> >> > +				vfront-porch = <1>;
> >> > +				hsync-len = <41>;
> >> > +				vsync-len = <2>;
> >> > +				hsync-active = <1>;
> >> > +				vsync-active = <1>;
> >> > +			};
> >> > +		};
> >> > +	};
> >> > +};
> >> > +
> >> > diff --git a/drivers/gpu/drm/Kconfig b/drivers/gpu/drm/Kconfig
> >> > index 151a050..a6957aa 100644
> >> > --- a/drivers/gpu/drm/Kconfig
> >> > +++ b/drivers/gpu/drm/Kconfig
> >> > @@ -199,6 +199,8 @@ source "drivers/gpu/drm/bochs/Kconfig"
> >> >
> >> >  source "drivers/gpu/drm/msm/Kconfig"
> >> >
> >> > +source "drivers/gpu/drm/fsl/Kconfig"
> >> > +
> >> >  source "drivers/gpu/drm/tegra/Kconfig"
> >> >
> >> >  source "drivers/gpu/drm/panel/Kconfig"
> >> > diff --git a/drivers/gpu/drm/Makefile b/drivers/gpu/drm/Makefile
> >> > index 2c239b9..ab5b9ef 100644
> >> > --- a/drivers/gpu/drm/Makefile
> >> > +++ b/drivers/gpu/drm/Makefile
> >> > @@ -56,6 +56,7 @@ obj-$(CONFIG_DRM_UDL) += udl/
> >> >  obj-$(CONFIG_DRM_AST) += ast/
> >> >  obj-$(CONFIG_DRM_ARMADA) += armada/
> >> >  obj-$(CONFIG_DRM_ATMEL_HLCDC)	+= atmel-hlcdc/
> >> > +obj-$(CONFIG_DRM_FSL_DCU) += fsl/
> >>
> >> Hm, I'm wondering whether it would be a good idea to store that driver
> >> under fsl-dcu/... Any opinion?
> >>
> >
> > I think it is good advice, I'll think about this
> >
> >> >  obj-$(CONFIG_DRM_RCAR_DU) += rcar-du/
> >> >  obj-$(CONFIG_DRM_SHMOBILE) +=shmobile/
> >> >  obj-$(CONFIG_DRM_OMAP)	+= omapdrm/
> >> > diff --git a/drivers/gpu/drm/fsl/Kconfig
> b/drivers/gpu/drm/fsl/Kconfig
> >> > new file mode 100644
> >> > index 0000000..e4f8df0
> >> > --- /dev/null
> >> > +++ b/drivers/gpu/drm/fsl/Kconfig
> >> > @@ -0,0 +1,17 @@
> >> > +config DRM_FSL_DCU
> >> > +	tristate "DRM Support for Freescale DCU"
> >> > +	depends on DRM && OF && ARM
> >> > +	select DRM_KMS_HELPER
> >> > +	select DRM_KMS_CMA_HELPER
> >> > +	select VIDEOMODE_HELPERS
> >> > +	select BACKLIGHT_CLASS_DEVICE
> >> > +	select BACKLIGHT_LCD_SUPPORT
> >> > +	select REGMAP_MMIO
> >> > +	select DRM_KMS_FB_HELPER
> >> > +	select FB_SYS_FILLRECT
> >> > +	select FB_SYS_COPYAREA
> >> > +	select FB_SYS_IMAGEBLIT
> >> > +	select FB_SYS_FOPS
> >> > +	help
> >> > +	  Choose this option if you have an Freescale DCU chipset.
> >> > +	  If M is selected the module will be called fsl-dcu-drm.
> >> > diff --git a/drivers/gpu/drm/fsl/Makefile
> b/drivers/gpu/drm/fsl/Makefile
> >> > new file mode 100644
> >> > index 0000000..5f74aee
> >> > --- /dev/null
> >> > +++ b/drivers/gpu/drm/fsl/Makefile
> >> > @@ -0,0 +1,8 @@
> >> > +fsl-dcu-drm-y := fsl_dcu_drm_drv.o \
> >> > +	       fsl_dcu_drm_kms.o \
> >> > +	       fsl_dcu_drm_connector.o \
> >> > +	       fsl_dcu_drm_plane.o \
> >> > +	       fsl_dcu_drm_crtc.o \
> >> > +	       fsl_dcu_drm_fbdev.o \
> >> > +
> >> > +obj-$(CONFIG_DRM_FSL_DCU)	+= fsl-dcu-drm.o
> >> > diff --git a/drivers/gpu/drm/fsl/fsl_dcu_drm_connector.c
> >> > b/drivers/gpu/drm/fsl/fsl_dcu_drm_connector.c
> >> > new file mode 100644
> >> > index 0000000..4610647
> >> > --- /dev/null
> >> > +++ b/drivers/gpu/drm/fsl/fsl_dcu_drm_connector.c
> >> > @@ -0,0 +1,193 @@
> >> > +/*
> >> > + * Copyright 2015 Freescale Semiconductor, Inc.
> >> > + *
> >> > + * Freescale DCU drm device driver
> >> > + *
> >> > + * This program is free software; you can redistribute it and/or
> modify
> >> > + * it under the terms of the GNU General Public License as published
> by
> >> > + * the Free Software Foundation; either version 2 of the License, or
> >> > + * (at your option) any later version.
> >> > + */
> >> > +
> >> > +#include <linux/backlight.h>
> >> > +
> >> > +#include <drm/drmP.h>
> >> > +#include <drm/drm_atomic_helper.h>
> >> > +#include <video/of_display_timing.h>
> >> > +
> >> > +#include "fsl_dcu_drm_drv.h"
> >> > +#include "fsl_dcu_drm_connector.h"
> >> > +
> >> > +static void fsl_dcu_drm_encoder_dpms(struct drm_encoder *encoder,
> int
> >> mode)
> >> > +{
> >> > +}
> >> > +
> >> > +static void fsl_dcu_drm_encoder_mode_prepare(struct drm_encoder
> >> *encoder)
> >> > +{
> >> > +}
> >> > +
> >> > +static void fsl_dcu_drm_encoder_mode_set(struct drm_encoder *encoder,
> >> > +					 struct drm_display_mode *mode,
> >> > +					 struct drm_display_mode
> *adjusted_mode)
> >> > +{
> >> > +}
> >> > +
> >> > +static void fsl_dcu_drm_encoder_mode_commit(struct drm_encoder
> *encoder)
> >> > +{
> >> > +}
> >> > +
> >> > +static void fsl_dcu_drm_encoder_disable(struct drm_encoder *encoder)
> >> > +{
> >> > +}
> >> > +
> >> > +static int
> >> > +fsl_dcu_drm_encoder_atomic_check(struct drm_encoder *encoder,
> >> > +				 struct drm_crtc_state *crtc_state,
> >> > +				 struct drm_connector_state *conn_state)
> >> > +{
> >> > +	return 0;
> >> > +}
> >> > +
> >> > +static void fsl_dcu_drm_encoder_destroy(struct drm_encoder *encoder)
> >> > +{
> >> > +	drm_encoder_cleanup(encoder);
> >> > +}
> >> > +
> >> > +static const struct drm_encoder_helper_funcs encoder_helper_funcs =
> {
> >> > +	.dpms = fsl_dcu_drm_encoder_dpms,
> >> > +	.prepare = fsl_dcu_drm_encoder_mode_prepare,
> >> > +	.commit = fsl_dcu_drm_encoder_mode_commit,
> >> > +	.mode_set = fsl_dcu_drm_encoder_mode_set,
> >> > +	.disable = fsl_dcu_drm_encoder_disable,
> >> > +	.atomic_check = fsl_dcu_drm_encoder_atomic_check,
> >> > +};
> >> > +
> >> > +static const struct drm_encoder_funcs encoder_funcs = {
> >> > +	.destroy = fsl_dcu_drm_encoder_destroy,
> >> > +};
> >> > +
> >> > +int fsl_dcu_drm_encoder_create(struct fsl_dcu_drm_device *fsl_dev,
> >> > +			       struct fsl_dcu_drm_crtc *crtc)
> >> > +{
> >> > +	struct drm_encoder *encoder = &fsl_dev->encoder;
> >> > +	int ret;
> >> > +
> >> > +	ret = drm_encoder_init(fsl_dev->ddev, encoder, &encoder_funcs,
> >> > +			       DRM_MODE_ENCODER_LVDS);
> >> > +	if (ret < 0)
> >> > +		return ret;
> >> > +
> >> > +	drm_encoder_helper_add(encoder, &encoder_helper_funcs);
> >> > +	encoder->crtc = &crtc->crtc;
> >> > +
> >> > +	return 0;
> >> > +}
> >> > +
> >> > +#define to_fsl_dcu_connector(connector) \
> >> > +	container_of(connector, struct fsl_dcu_drm_connector,
> connector)
> >> > +
> >> > +static int fsl_dcu_drm_connector_get_modes(struct drm_connector
> >> *connector)
> >> > +{
> >> > +	struct drm_device *dev = connector->dev;
> >> > +	struct device_node *display_np, *np = dev->dev->of_node;
> >> > +	struct drm_display_mode *mode = drm_mode_create(connector-
> >dev);
> >> > +	int num_modes = 0;
> >> > +
> >> > +	if (np) {
> >> > +		display_np = of_parse_phandle(np, "display", 0);
> >> > +		if (!display_np) {
> >> > +			dev_err(dev->dev, "failed to find display
> phandle\n");
> >> > +			return num_modes;
> >> > +		}
> >> > +		of_get_drm_display_mode(display_np, mode,
> OF_USE_NATIVE_MODE);
> >> > +		mode->type |= DRM_MODE_TYPE_DRIVER |
> DRM_MODE_TYPE_PREFERRED,
> >> > +		drm_mode_probed_add(connector, mode);
> >> > +		num_modes++;
> >> > +	}
> >> > +
> >> > +	return num_modes;
> >> > +}
> >> > +
> >> > +static int fsl_dcu_drm_connector_mode_valid(struct drm_connector
> >> *connector,
> >> > +					    struct drm_display_mode *mode)
> >> > +{
> >> > +	return MODE_OK;
> >> > +}
> >> > +
> >> > +static struct drm_encoder *
> >> > +fsl_dcu_drm_connector_best_encoder(struct drm_connector *connector)
> >> > +{
> >> > +	struct fsl_dcu_drm_connector *fsl_con =
> >> to_fsl_dcu_connector(connector);
> >> > +
> >> > +	return fsl_con->encoder;
> >> > +}
> >> > +
> >> > +static void fsl_dcu_drm_connector_destroy(struct drm_connector
> >> *connector)
> >> > +{
> >> > +	drm_connector_unregister(connector);
> >> > +	drm_connector_cleanup(connector);
> >> > +}
> >> > +
> >> > +static enum drm_connector_status
> >> > +fsl_dcu_drm_connector_detect(struct drm_connector *connector, bool
> >> force)
> >> > +{
> >> > +	return connector_status_connected;
> >> > +}
> >> > +
> >> > +static const struct drm_connector_funcs fsl_dcu_drm_connector_funcs
> = {
> >> > +	.dpms = drm_atomic_helper_connector_dpms,
> >> > +	.reset = drm_atomic_helper_connector_reset,
> >> > +	.detect = fsl_dcu_drm_connector_detect,
> >> > +	.fill_modes = drm_helper_probe_single_connector_modes,
> >> > +	.destroy = fsl_dcu_drm_connector_destroy,
> >> > +	.atomic_duplicate_state =
> >> drm_atomic_helper_connector_duplicate_state,
> >> > +	.atomic_destroy_state =
> drm_atomic_helper_connector_destroy_state,
> >> > +};
> >> > +
> >> > +static const struct drm_connector_helper_funcs
> connector_helper_funcs =
> >> {
> >> > +	.get_modes = fsl_dcu_drm_connector_get_modes,
> >> > +	.mode_valid = fsl_dcu_drm_connector_mode_valid,
> >> > +	.best_encoder = fsl_dcu_drm_connector_best_encoder,
> >> > +};
> >> > +
> >> > +int fsl_dcu_drm_connector_create(struct fsl_dcu_drm_device *fsl_dev,
> >> > +				 struct drm_encoder *encoder)
> >> > +{
> >> > +	struct drm_connector *connector = &fsl_dev-
> >connector.connector;
> >> > +	int ret;
> >> > +
> >> > +	fsl_dev->connector.encoder = encoder;
> >> > +
> >> > +	connector->display_info.width_mm = 0;
> >> > +	connector->display_info.height_mm = 0;
> >> > +
> >> > +	ret = drm_connector_init(fsl_dev->ddev, connector,
> >> > +				 &fsl_dcu_drm_connector_funcs,
> >> > +				 DRM_MODE_CONNECTOR_LVDS);
> >> > +	if (ret < 0)
> >> > +		return ret;
> >> > +
> >> > +	connector->dpms = DRM_MODE_DPMS_OFF;
> >> > +	drm_connector_helper_add(connector, &connector_helper_funcs);
> >> > +	ret = drm_connector_register(connector);
> >> > +	if (ret < 0)
> >> > +		goto err_cleanup;
> >> > +
> >> > +	ret = drm_mode_connector_attach_encoder(connector, encoder);
> >> > +	if (ret < 0)
> >> > +		goto err_sysfs;
> >> > +
> >> > +	connector->encoder = encoder;
> >> > +
> >> > +	drm_object_property_set_value
> >> > +		(&connector->base, fsl_dev->ddev-
> >mode_config.dpms_property,
> >> > +		DRM_MODE_DPMS_OFF);
> >> > +
> >> > +	return 0;
> >> > +
> >> > +err_sysfs:
> >> > +	drm_connector_unregister(connector);
> >> > +err_cleanup:
> >> > +	drm_connector_cleanup(connector);
> >> > +	return ret;
> >> > +}
> >> > diff --git a/drivers/gpu/drm/fsl/fsl_dcu_drm_connector.h
> >> > b/drivers/gpu/drm/fsl/fsl_dcu_drm_connector.h
> >> > new file mode 100644
> >> > index 0000000..bbf6d38
> >> > --- /dev/null
> >> > +++ b/drivers/gpu/drm/fsl/fsl_dcu_drm_connector.h
> >> > @@ -0,0 +1,30 @@
> >> > +/*
> >> > + * Copyright 2015 Freescale Semiconductor, Inc.
> >> > + *
> >> > + * Freescale DCU drm device driver
> >> > + *
> >> > + * 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 __FSL_DCU_DRM_CONNECTOR_H__
> >> > +#define __FSL_DCU_DRM_CONNECTOR_H__
> >> > +
> >> > +#include <drm/drmP.h>
> >> > +#include <drm/drm_crtc.h>
> >> > +#include "fsl_dcu_drm_crtc.h"
> >> > +
> >> > +struct fsl_dcu_drm_device;
> >> > +struct fsl_dcu_drm_connector {
> >> > +	struct drm_connector connector;
> >> > +	struct drm_encoder *encoder;
> >> > +};
> >> > +
> >> > +int fsl_dcu_drm_encoder_create(struct fsl_dcu_drm_device *fsl_dev,
> >> > +			       struct fsl_dcu_drm_crtc *crtc);
> >> > +int fsl_dcu_drm_connector_create(struct fsl_dcu_drm_device *fsl_dev,
> >> > +				 struct drm_encoder *encoder);
> >> > +
> >> > +#endif /* __FSL_DCU_DRM_CONNECTOR_H__ */
> >> > diff --git a/drivers/gpu/drm/fsl/fsl_dcu_drm_crtc.c
> >> > b/drivers/gpu/drm/fsl/fsl_dcu_drm_crtc.c
> >> > new file mode 100644
> >> > index 0000000..076e273
> >> > --- /dev/null
> >> > +++ b/drivers/gpu/drm/fsl/fsl_dcu_drm_crtc.c
> >> > @@ -0,0 +1,165 @@
> >> > +/*
> >> > + * Copyright 2015 Freescale Semiconductor, Inc.
> >> > + *
> >> > + * Freescale DCU drm device driver
> >> > + *
> >> > + * This program is free software; you can redistribute it and/or
> modify
> >> > + * it under the terms of the GNU General Public License as published
> by
> >> > + * the Free Software Foundation; either version 2 of the License, or
> >> > + * (at your option) any later version.
> >> > + */
> >> > +
> >> > +#include <linux/regmap.h>
> >> > +#include <linux/clk.h>
> >> > +
> >> > +#include <drm/drmP.h>
> >> > +#include <drm/drm_atomic.h>
> >> > +#include <drm/drm_atomic_helper.h>
> >> > +#include <drm/drm_crtc.h>
> >> > +
> >> > +#include "fsl_dcu_drm_crtc.h"
> >> > +#include "fsl_dcu_drm_drv.h"
> >> > +#include "fsl_dcu_drm_plane.h"
> >> > +
> >> > +#define to_fsl_dcu_crtc(c)	container_of(c, struct
> fsl_dcu_drm_crtc,
> >> crtc)
> >> > +
> >> > +void fsl_dcu_drm_crtc_suspend(struct drm_crtc *crtc)
> >> > +{
> >> > +}
> >> > +
> >> > +static void fsl_dcu_drm_crtc_mode_set_nofb(struct drm_crtc *crtc)
> >> > +{
> >> > +	struct drm_device *dev = crtc->dev;
> >> > +	struct fsl_dcu_drm_device *fsl_dev = dev->dev_private;
> >> > +	struct drm_display_mode *mode = &crtc->state->mode;
> >> > +	uint32_t hbp, hfp, hsw, vbp, vfp, vsw, div, index;
> >> > +
> >> > +	DBG(": set mode: %d:\"%s\" %d %d %d %d %d %d %d %d %d %d 0x%x
> 0x%x",
> >> > +	    mode->base.id, mode->name,
> >> > +	    mode->vrefresh, mode->clock,
> >> > +	    mode->hdisplay, mode->hsync_start,
> >> > +	    mode->hsync_end, mode->htotal,
> >> > +	    mode->vdisplay, mode->vsync_start,
> >> > +	    mode->vsync_end, mode->vtotal,
> >> > +	    mode->type, mode->flags);
> >> > +
> >> > +	index = drm_crtc_index(crtc);
> >> > +	div = (uint32_t)clk_get_rate(fsl_dev->clk) / mode->clock /
> 1000;
> >> > +
> >> > +	/* Configure timings: */
> >> > +	hbp = mode->htotal - mode->hsync_end;
> >> > +	hfp = mode->hsync_start - mode->hdisplay;
> >> > +	hsw = mode->hsync_end - mode->hsync_start;
> >> > +	vbp = mode->vtotal - mode->vsync_end;
> >> > +	vfp = mode->vsync_start - mode->vdisplay;
> >> > +	vsw = mode->vsync_end - mode->vsync_start;
> >> > +
> >> > +	regmap_write(fsl_dev->regmap, DCU_HSYN_PARA,
> >> > +		     DCU_HSYN_PARA_BP(hbp) |
> >> > +		     DCU_HSYN_PARA_PW(hsw) |
> >> > +		     DCU_HSYN_PARA_FP(hfp));
> >> > +	regmap_write(fsl_dev->regmap, DCU_VSYN_PARA,
> >> > +		     DCU_VSYN_PARA_BP(vbp) |
> >> > +		     DCU_VSYN_PARA_PW(vsw) |
> >> > +		     DCU_VSYN_PARA_FP(vfp));
> >> > +	regmap_write(fsl_dev->regmap, DCU_DISP_SIZE,
> >> > +		     DCU_DISP_SIZE_DELTA_Y(mode->vdisplay) |
> >> > +		     DCU_DISP_SIZE_DELTA_X(mode->hdisplay));
> >> > +	regmap_write(fsl_dev->regmap, DCU_DIV_RATIO, div);
> >> > +	regmap_write(fsl_dev->regmap, DCU_UPDATE_MODE,
> >> DCU_UPDATE_MODE_READREG);
> >> > +}
> >> > +
> >> > +static bool fsl_dcu_drm_crtc_mode_fixup(struct drm_crtc *crtc,
> >> > +					const struct drm_display_mode *mode,
> >> > +					struct drm_display_mode *adjusted_mode)
> >> > +{
> >> > +	return true;
> >> > +}
> >> > +
> >> > +static void fsl_dcu_drm_crtc_prepare(struct drm_crtc *crtc)
> >> > +{
> >> > +}
> >> > +
> >> > +/* Now enable the clocks, plane, pipe, and connectors that we set up.
> >> */
> >> > +static void fsl_dcu_drm_crtc_mode_commit(struct drm_crtc *crtc)
> >> > +{
> >> > +}
> >> > +
> >> > +static int fsl_dcu_drm_crtc_atomic_check(struct drm_crtc *crtc,
> >> > +					 struct drm_crtc_state *state)
> >> > +{
> >> > +	return 0;
> >> > +}
> >> > +
> >> > +static void fsl_dcu_drm_crtc_atomic_begin(struct drm_crtc *crtc)
> >> > +{
> >> > +}
> >> > +
> >> > +static void fsl_dcu_drm_crtc_atomic_flush(struct drm_crtc *crtc)
> >> > +{
> >> > +}
> >> > +
> >> > +static void fsl_dcu_drm_disable_crtc(struct drm_crtc *crtc)
> >> > +{
> >> > +}
> >> > +
> >> > +static const struct drm_crtc_funcs fsl_dcu_drm_crtc_funcs = {
> >> > +	.page_flip = drm_atomic_helper_page_flip,
> >> > +	.set_config = drm_atomic_helper_set_config,
> >> > +	.destroy = drm_crtc_cleanup,
> >> > +	.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 void fsl_dcu_drm_crtc_dpms(struct drm_crtc *crtc, int mode)
> >> > +{
> >> > +}
> >> > +
> >> > +static const struct drm_crtc_helper_funcs
> fsl_dcu_drm_crtc_helper_funcs
> >> = {
> >> > +	.disable = fsl_dcu_drm_disable_crtc,
> >> > +	.mode_fixup = fsl_dcu_drm_crtc_mode_fixup,
> >> > +	.mode_set = drm_helper_crtc_mode_set,
> >> > +	.mode_set_nofb = fsl_dcu_drm_crtc_mode_set_nofb,
> >> > +	.mode_set_base = drm_helper_crtc_mode_set_base,
> >> > +	.prepare = fsl_dcu_drm_crtc_prepare,
> >> > +	.commit = fsl_dcu_drm_crtc_mode_commit,
> >> > +	.atomic_check = fsl_dcu_drm_crtc_atomic_check,
> >> > +	.atomic_begin = fsl_dcu_drm_crtc_atomic_begin,
> >> > +	.atomic_flush = fsl_dcu_drm_crtc_atomic_flush,
> >> > +	.dpms = fsl_dcu_drm_crtc_dpms,
> >> > +};
> >> > +
> >> > +int fsl_dcu_drm_crtc_create(struct fsl_dcu_drm_device *fsl_dev)
> >> > +{
> >> > +	struct drm_plane *primary;
> >> > +	struct drm_crtc *crtc = &fsl_dev->crtc.crtc;
> >> > +	int ret;
> >> > +
> 
> 
> I hit an issue on some Vybrid devices because the planes have not been
> properly initialized. It seems that initialization of planes is required
> for Vybrid, something like this was also part of the DCU fbdev driver
> submitted by Alison Wang:
> 
> +#define DCU_TOTAL_LAYER_NUM    64
>  int fsl_dcu_drm_crtc_create(struct fsl_dcu_drm_device *fsl_dev)
>  {
>         struct drm_plane *primary;
>         struct drm_crtc *crtc = &fsl_dev->crtc.crtc;
>         int ret;
> +       int i;
> +
> +       for (i = 1; i < DCU_TOTAL_LAYER_NUM; i++) {
> +               regmap_write(fsl_dev->regmap, DCU_CTRLDESCLN_1(i), 0);
> +               regmap_write(fsl_dev->regmap, DCU_CTRLDESCLN_2(i), 0);
> +               regmap_write(fsl_dev->regmap, DCU_CTRLDESCLN_3(i), 0);
> +               regmap_write(fsl_dev->regmap, DCU_CTRLDESCLN_4(i), 0);
> +               regmap_write(fsl_dev->regmap, DCU_CTRLDESCLN_5(i), 0);
> +               regmap_write(fsl_dev->regmap, DCU_CTRLDESCLN_6(i), 0);
> +               regmap_write(fsl_dev->regmap, DCU_CTRLDESCLN_7(i), 0);
> +               regmap_write(fsl_dev->regmap, DCU_CTRLDESCLN_8(i), 0);
> +               regmap_write(fsl_dev->regmap, DCU_CTRLDESCLN_9(i), 0);
> +       }
> +       regmap_write(fsl_dev->regmap, DCU_UPDATE_MODE,
> DCU_UPDATE_MODE_READREG);
> 
>         fsl_dev->crtc.dpms = DRM_MODE_DPMS_OFF;
> 
> 
> Not sure if this is required for ls1021a too...
> 

I have tested that there is no influence on ls1021a whether doing this initialization.
If it is a mast for Vybrid device, I will add layers initialization.

> 
> >> > +	fsl_dev->crtc.dpms = DRM_MODE_DPMS_OFF;
> >> > +
> >> > +	primary = fsl_dcu_drm_primary_create_plane(fsl_dev->ddev);
> >> > +	ret = drm_crtc_init_with_planes(fsl_dev->ddev, crtc, primary,
> NULL,
> >> > +					&fsl_dcu_drm_crtc_funcs);
> >> > +	if (ret < 0)
> >> > +		return ret;
> >> > +
> >> > +	drm_crtc_helper_add(crtc, &fsl_dcu_drm_crtc_helper_funcs);
> >> > +
> >> > +	regmap_write(fsl_dev->regmap, DCU_SYN_POL,
> >> > +		     DCU_SYN_POL_INV_VS_LOW | DCU_SYN_POL_INV_HS_LOW);
> >> > +	regmap_write(fsl_dev->regmap, DCU_BGND, DCU_BGND_R(0) |
> >> > +		     DCU_BGND_G(0) | DCU_BGND_B(0));
> >> > +	regmap_write(fsl_dev->regmap, DCU_DCU_MODE,
> >> > +		     DCU_MODE_BLEND_ITER(1) | DCU_MODE_RASTER_EN);
> >> > +	regmap_write(fsl_dev->regmap, DCU_THRESHOLD,
> >> > +		     DCU_THRESHOLD_LS_BF_VS(BF_VS_VAL) |
> >> > +		     DCU_THRESHOLD_OUT_BUF_HIGH(BUF_MAX_VAL) |
> >> > +		     DCU_THRESHOLD_OUT_BUF_LOW(BUF_MIN_VAL));
> >> > +	regmap_update_bits(fsl_dev->regmap, DCU_DCU_MODE,
> >> > +			   DCU_MODE_DCU_MODE_MASK,
> >> > +			   DCU_MODE_DCU_MODE(DCU_MODE_OFF));
> >> > +	regmap_write(fsl_dev->regmap, DCU_UPDATE_MODE,
> >> DCU_UPDATE_MODE_READREG);
> >> > +
> >> > +	return 0;
> >> > +}
> >> > diff --git a/drivers/gpu/drm/fsl/fsl_dcu_drm_crtc.h
> >> > b/drivers/gpu/drm/fsl/fsl_dcu_drm_crtc.h
> >> > new file mode 100644
> >> > index 0000000..d44b564
> >> > --- /dev/null
> >> > +++ b/drivers/gpu/drm/fsl/fsl_dcu_drm_crtc.h
> >> > @@ -0,0 +1,26 @@
> >> > +/*
> >> > + * Copyright 2015 Freescale Semiconductor, Inc.
> >> > + *
> >> > + * Freescale DCU drm device driver
> >> > + *
> >> > + * 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 __FSL_DCU_DRM_CRTC_H__
> >> > +#define __FSL_DCU_DRM_CRTC_H__
> >> > +
> >> > +#include <drm/drmP.h>
> >> > +#include <drm/drm_crtc.h>
> >> > +
> >> > +struct fsl_dcu_drm_device;
> >> > +struct fsl_dcu_drm_crtc {
> >> > +	struct drm_crtc crtc;
> >> > +	int dpms;
> >> > +};
> >> > +
> >> > +int fsl_dcu_drm_crtc_create(struct fsl_dcu_drm_device *fsl_dev);
> >> > +
> >> > +#endif /* __FSL_DCU_DRM_CRTC_H__ */
> >> > diff --git a/drivers/gpu/drm/fsl/fsl_dcu_drm_drv.c
> >> > b/drivers/gpu/drm/fsl/fsl_dcu_drm_drv.c
> >> > new file mode 100644
> >> > index 0000000..d4a559a
> >> > --- /dev/null
> >> > +++ b/drivers/gpu/drm/fsl/fsl_dcu_drm_drv.c
> >> > @@ -0,0 +1,331 @@
> >> > +/*
> >> > + * Copyright 2015 Freescale Semiconductor, Inc.
> >> > + *
> >> > + * Freescale DCU drm device driver
> >> > + *
> >> > + * This program is free software; you can redistribute it and/or
> modify
> >> > + * it under the terms of the GNU General Public License as published
> by
> >> > + * the Free Software Foundation; either version 2 of the License, or
> >> > + * (at your option) any later version.
> >> > + */
> >> > +
> >> > +#include <linux/clk.h>
> >> > +#include <linux/io.h>
> >> > +#include <linux/mm.h>
> >> > +#include <linux/module.h>
> >> > +#include <linux/of_platform.h>
> >> > +#include <linux/platform_device.h>
> >> > +#include <linux/pm.h>
> >> > +#include <linux/pm_runtime.h>
> >> > +#include <linux/regmap.h>
> >> > +
> >> > +#include <drm/drmP.h>
> >> > +#include <linux/fsl/dcu.h>
> >>
> >> This file seems to be missing in that patch.
> >>
> >
> > This file in patch 2/4, It's LS1021A platform related code.
> >
> 
> This is not allowed in the kernel world: Each commit need to represent a
> complete change in the sense of being compileable and runnable. This is
> required to bisect kernel issues. Git bisect helps isolate issues by
> selecting random commits. If someone is using git bisect, and git
> happens to choose to test this exact revision, the developer will sit in
> front of a broken kernel. Whenever possible, we try to avoid that.
> 
> In this case, you can easily avoid that by moving patch 2/4 in front of
> this patch. Then the file will be there when the driver is using it.
> 

I will adjust the sequence properly. Thank you again, I learn a lot from you.

> However, as I already stated in v2 of the patchset, I don't think that
> direct calls into arch are the right solution to enable the pixel clock.
> To me, that looks like a clock gate which asks for the common clock
> framework being used, e.g. the clk-gate driver:
> http://lxr.free-electrons.com/source/drivers/clk/clk-gate.c
> 
> The DCU clock gates in Vybrid use this driver too, see:
> http://lxr.free-electrons.com/source/arch/arm/mach-imx/clk-vf610.c#L317
> 
> --
> Stefan
> 

Hum... I think this clock may not as you considered. This clock is pixel clock
rather than DCU module clock. Enable it means allow the clock export to the pixel pin
from DCU module. Common clock framework isn't suitable for managing this clock.

--
Jianwei
> 
> >> > +
> >> > +#include "fsl_dcu_drm_drv.h"
> >> > +#include "fsl_dcu_drm_kms.h"
> >> > +
> >> > +static int fsl_dcu_unload(struct drm_device *dev)
> >> > +{
> >> > +	drm_mode_config_cleanup(dev);
> >> > +	drm_vblank_cleanup(dev);
> >> > +	drm_irq_uninstall(dev);
> >> > +
> >> > +	dev->dev_private = NULL;
> >> > +
> >> > +	return 0;
> >> > +}
> >> > +
> >> > +static struct regmap_config fsl_dcu_regmap_config = {
> >> > +	.reg_bits = 32,
> >> > +	.reg_stride = 4,
> >> > +	.val_bits = 32,
> >> > +};
> >> > +
> >> > +static int fsl_dcu_bypass_tcon(struct fsl_dcu_drm_device *fsl_dev,
> >> > +			       struct device_node *np)
> >> > +{
> >> > +	struct device_node *tcon_np;
> >> > +	struct platform_device *pdev;
> >> > +	struct clk *tcon_clk;
> >> > +	struct resource *res;
> >> > +	void __iomem *base;
> >> > +
> >> > +	tcon_np = of_parse_phandle(np, "tcon-controller", 0);
> >> > +	if (!tcon_np)
> >> > +		return -EINVAL;
> >> > +
> >> > +	pdev = of_find_device_by_node(tcon_np);
> >> > +	if (!pdev)
> >> > +		return -EINVAL;
> >> > +
> >> > +	tcon_clk = devm_clk_get(&pdev->dev, "tcon");
> >> > +	if (IS_ERR(tcon_clk))
> >> > +		return PTR_ERR(tcon_clk);
> >> > +	clk_prepare_enable(tcon_clk);
> >>
> >> You enable the clock explicitly...
> >>
> >> > +
> >> > +	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> >> > +	if (!res)
> >> > +		return -ENODEV;
> >> > +
> >> > +	base = devm_ioremap_resource(&pdev->dev, res);
> >> > +	if (IS_ERR(base))
> >> > +		return PTR_ERR(base);
> >> > +
> >> > +	fsl_dev->tcon_regmap = devm_regmap_init_mmio_clk(&pdev->dev,
> >> > +			"tcon", base, &fsl_dcu_regmap_config);
> >>
> >> And implicitly using regmap. In a short test on Vybrid, the clock is
> >> actually not needed during operation, hence we could use the explicit
> >> enabling above, what do you think?
> >>
> >> Also, the clock and tcon in general currently does not get handled by
> >> suspend/resume code...
> >>
> >
> > OK, I'll update code here
> >
> >> > +	if (IS_ERR(fsl_dev->tcon_regmap)) {
> >> > +		dev_err(&pdev->dev, "regmap init failed\n");
> >> > +		return PTR_ERR(fsl_dev->tcon_regmap);
> >> > +	}
> >> > +
> >> > +	regmap_write(fsl_dev->tcon_regmap, TCON_CTRL1,
> TCON_BYPASS_ENABLE);
> >> > +	return 0;
> >> > +}
> >> > +
> >> > +static int fsl_dcu_drm_irq_init(struct drm_device *dev)
> >> > +{
> >> > +	struct platform_device *pdev = dev->platformdev;
> >> > +	struct fsl_dcu_drm_device *fsl_dev = dev->dev_private;
> >> > +	unsigned int int_mask;
> >> > +	int ret;
> >> > +
> >> > +	ret = drm_irq_install(dev, platform_get_irq(dev->platformdev,
> 0));
> >> > +	if (ret < 0)
> >> > +		dev_err(&pdev->dev, "failed to install IRQ handler\n");
> >> > +
> >> > +	dev->irq_enabled = true;
> >> > +	dev->vblank_disable_allowed = true;
> >> > +
> >> > +	regmap_write(fsl_dev->regmap, DCU_INT_STATUS, 0);
> >> > +	regmap_read(fsl_dev->regmap, DCU_INT_MASK, &int_mask);
> >> > +	regmap_write(fsl_dev->regmap, DCU_INT_MASK, int_mask &
> >> > +		     ~DCU_INT_MASK_VBLANK);
> >> > +	regmap_write(fsl_dev->regmap, DCU_UPDATE_MODE,
> >> DCU_UPDATE_MODE_READREG);
> >> > +
> >> > +	return 0;
> >> > +}
> >> > +
> >> > +static int fsl_dcu_load(struct drm_device *dev, unsigned long flags)
> >> > +{
> >> > +	struct platform_device *pdev = dev->platformdev;
> >> > +	struct fsl_dcu_drm_device *fsl_dev;
> >> > +	struct resource *res;
> >> > +	void __iomem *base;
> >> > +	int ret;
> >> > +
> >> > +	fsl_dev = devm_kzalloc(&pdev->dev, sizeof(*fsl_dev),
> GFP_KERNEL);
> >> > +	if (!fsl_dev)
> >> > +		return -ENOMEM;
> >> > +
> >> > +	fsl_dev->dev = &pdev->dev;
> >> > +	fsl_dev->ddev = dev;
> >> > +	fsl_dev->np = pdev->dev.of_node;
> >> > +	dev->dev_private = fsl_dev;
> >> > +	drm_dev_set_unique(dev, dev_name(dev->dev));
> >> > +
> >> > +	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> >> > +	if (!res) {
> >> > +		dev_err(&pdev->dev, "could not get memory IO
> resource\n");
> >> > +		return -ENODEV;
> >> > +	}
> >> > +
> >> > +	base = devm_ioremap_resource(&pdev->dev, res);
> >> > +	if (IS_ERR(base)) {
> >> > +		ret = PTR_ERR(base);
> >> > +		return ret;
> >> > +	}
> >> > +
> >> > +	fsl_dev->regmap = devm_regmap_init_mmio_clk(&pdev->dev, NULL,
> >> > +			base, &fsl_dcu_regmap_config);
> >> > +	if (IS_ERR(fsl_dev->regmap)) {
> >> > +		dev_err(&pdev->dev, "regmap init failed\n");
> >> > +		return PTR_ERR(fsl_dev->regmap);
> >> > +	}
> >> > +
> >> > +	/* Put TCON in bypass mode, so the input signals from DCU are
> passed
> >> > +	 * through TCON unchanged */
> >> > +	fsl_dcu_bypass_tcon(fsl_dev, fsl_dev->np);
> >> > +	fsl_dev->clk = devm_clk_get(&pdev->dev, "dcu");
> >> > +	if (IS_ERR(fsl_dev->clk)) {
> >> > +		ret = PTR_ERR(fsl_dev->clk);
> >> > +		dev_err(&pdev->dev, "could not get clock\n");
> >> > +		return ret;
> >> > +	}
> >> > +	clk_prepare_enable(fsl_dev->clk);
> >> > +	dev_set_drvdata(dev->dev, fsl_dev);
> >> > +
> >> > +	ret = fsl_dcu_drm_modeset_init(fsl_dev);
> >> > +	if (ret < 0) {
> >> > +		dev_err(&pdev->dev, "failed to initialize mode
> setting\n");
> >> > +		return ret;
> >> > +	}
> >> > +
> >> > +	ret = drm_vblank_init(dev, dev->mode_config.num_crtc);
> >> > +	if (ret < 0) {
> >> > +		dev_err(&pdev->dev, "failed to initialize vblank\n");
> >> > +		goto done;
> >> > +	}
> >> > +
> >> > +	ret = fsl_dcu_drm_irq_init(dev);
> >> > +	if (ret < 0)
> >> > +		goto done;
> >> > +
> >> > +	fsl_dcu_fbdev_init(dev);
> >> > +
> >> > +	return 0;
> >> > +done:
> >> > +	if (ret)
> >> > +		fsl_dcu_unload(dev);
> >> > +
> >> > +	return ret;
> >> > +}
> >> > +
> >> > +static void fsl_dcu_drm_preclose(struct drm_device *dev, struct
> >> drm_file *file)
> >> > +{
> >> > +	;
> >> > +}
> >> > +
> >> > +static irqreturn_t fsl_dcu_drm_irq(int irq, void *arg)
> >> > +{
> >> > +	struct drm_device *dev = arg;
> >> > +	struct fsl_dcu_drm_device *fsl_dev = dev->dev_private;
> >> > +	unsigned int int_status;
> >> > +
> >> > +	regmap_read(fsl_dev->regmap, DCU_INT_STATUS, &int_status);
> >> > +	if (int_status & DCU_INT_STATUS_VBLANK)
> >> > +		drm_handle_vblank(dev, 0);
> >> > +
> >> > +	regmap_write(fsl_dev->regmap, DCU_INT_STATUS, 0xffffffff);
> >> > +	regmap_write(fsl_dev->regmap, DCU_UPDATE_MODE,
> >> DCU_UPDATE_MODE_READREG);
> >> > +
> >> > +	return IRQ_HANDLED;
> >> > +}
> >> > +
> >> > +static int fsl_dcu_drm_enable_vblank(struct drm_device *dev, int
> crtc)
> >> > +{
> >> > +	return 0;
> >> > +}
> >> > +
> >> > +static void fsl_dcu_drm_disable_vblank(struct drm_device *dev, int
> crtc)
> >> > +{
> >> > +	;
> >> > +}
> >> > +
> >> > +static const struct file_operations fsl_dcu_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		= no_llseek,
> >> > +	.mmap		= drm_gem_cma_mmap,
> >> > +};
> >> > +
> >> > +static struct drm_driver fsl_dcu_drm_driver = {
> >> > +	.driver_features	= DRIVER_HAVE_IRQ | DRIVER_GEM |
> DRIVER_MODESET
> >> > +				| DRIVER_PRIME,
> >> > +	.load			= fsl_dcu_load,
> >> > +	.unload			= fsl_dcu_unload,
> >> > +	.preclose		= fsl_dcu_drm_preclose,
> >> > +	.irq_handler		= fsl_dcu_drm_irq,
> >> > +	.get_vblank_counter	= drm_vblank_count,
> >> > +	.enable_vblank		= fsl_dcu_drm_enable_vblank,
> >> > +	.disable_vblank		= fsl_dcu_drm_disable_vblank,
> >> > +	.gem_free_object	= drm_gem_cma_free_object,
> >> > +	.gem_vm_ops		= &drm_gem_cma_vm_ops,
> >> > +	.prime_handle_to_fd	= drm_gem_prime_handle_to_fd,
> >> > +	.prime_fd_to_handle	= drm_gem_prime_fd_to_handle,
> >> > +	.gem_prime_import	= drm_gem_prime_import,
> >> > +	.gem_prime_export	= drm_gem_prime_export,
> >> > +	.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,
> >> > +	.dumb_create		= drm_gem_cma_dumb_create,
> >> > +	.dumb_map_offset	= drm_gem_cma_dumb_map_offset,
> >> > +	.dumb_destroy		= drm_gem_dumb_destroy,
> >> > +	.fops			= &fsl_dcu_drm_fops,
> >> > +	.name			= "fsl-dcu-drm",
> >> > +	.desc			= "Freescale DCU DRM",
> >> > +	.date			= "20150213",
> >> > +	.major			= 1,
> >> > +	.minor			= 0,
> >> > +};
> >> > +
> >> > +#ifdef CONFIG_PM_SLEEP
> >> > +static int fsl_dcu_drm_pm_suspend(struct device *dev)
> >> > +{
> >> > +	struct fsl_dcu_drm_device *fsl_dev = dev_get_drvdata(dev);
> >> > +
> >> > +	if (of_device_is_compatible(fsl_dev->np, "fsl,ls1021a-dcu"))
> >> > +		dcu_pixclk_disable();
> >> > +
> >> > +	drm_kms_helper_poll_disable(fsl_dev->ddev);
> >> > +	fsl_dcu_drm_crtc_suspend(&fsl_dev->crtc);
> >>
> >> I get
> >>
> >> drivers/gpu/drm/fsl/fsl_dcu_drm_drv.c: In function
> >> 'fsl_dcu_drm_pm_suspend':
> >> drivers/gpu/drm/fsl/fsl_dcu_drm_drv.c:270:2: error: implicit
> declaration
> >> of function 'fsl_dcu_drm_crtc_suspend'
> >> [-Werror=implicit-function-declaration]
> >>   fsl_dcu_drm_crtc_suspend(&fsl_dev->crtc);
> >>   ^
> >> drivers/gpu/drm/fsl/fsl_dcu_drm_drv.c: In function
> >> 'fsl_dcu_drm_pm_resume':
> >> drivers/gpu/drm/fsl/fsl_dcu_drm_drv.c:280:2: error: implicit
> declaration
> >> of function 'fsl_dcu_drm_crtc_resume'
> >> [-Werror=implicit-function-declaration]
> >>   fsl_dcu_drm_crtc_resume(&fsl_dev->crtc);
> >>   ^
> >>
> >> The function fsl_dcu_drm_crtc_suspend seems to be part of
> >> fsl_dcu_drm_crtc.c, but is empty. While the other is missing
> >> completely... Please fix/remove as appropriate.
> >>
> >
> > OK, I'll fix it
> >
> > Regards
> > Jianwei
> >> > +
> >> > +	return 0;
> >> > +}
> >> > +
> >> > +static int fsl_dcu_drm_pm_resume(struct device *dev)
> >> > +{
> >> > +	struct fsl_dcu_drm_device *fsl_dev = dev_get_drvdata(dev);
> >> > +
> >> > +	drm_modeset_lock_all(fsl_dev->ddev);
> >> > +	fsl_dcu_drm_crtc_resume(&fsl_dev->crtc);
> >> > +	drm_modeset_unlock_all(fsl_dev->ddev);
> >> > +	drm_kms_helper_poll_enable(fsl_dev->ddev);
> >> > +
> >> > +	if (of_device_is_compatible(fsl_dev->np, "fsl,ls1021a-dcu"))
> >> > +		dcu_pixclk_enable();
> >> > +
> >> > +	return 0;
> >> > +}
> >> > +#endif
> >> > +
> >> > +static const struct dev_pm_ops fsl_dcu_drm_pm_ops = {
> >> > +	SET_SYSTEM_SLEEP_PM_OPS(fsl_dcu_drm_pm_suspend,
> >> fsl_dcu_drm_pm_resume)
> >> > +};
> >> > +
> >> > +static int fsl_dcu_drm_probe(struct platform_device *pdev)
> >> > +{
> >> > +	return drm_platform_init(&fsl_dcu_drm_driver, pdev);
> >> > +}
> >> > +
> >> > +static int fsl_dcu_drm_remove(struct platform_device *pdev)
> >> > +{
> >> > +	struct fsl_dcu_drm_device *fsl_dev =
> platform_get_drvdata(pdev);
> >> > +
> >> > +	drm_put_dev(fsl_dev->ddev);
> >> > +
> >> > +	return 0;
> >> > +}
> >> > +
> >> > +static const struct of_device_id fsl_dcu_of_match[] = {
> >> > +		{ .compatible = "fsl,ls1021a-dcu", },
> >> > +		{ .compatible = "fsl,vf610-dcu", },
> >> > +		{ },
> >> > +};
> >> > +MODULE_DEVICE_TABLE(of, fsl_dcu_of_match);
> >> > +
> >> > +static struct platform_driver fsl_dcu_drm_platform_driver = {
> >> > +	.probe		= fsl_dcu_drm_probe,
> >> > +	.remove		= fsl_dcu_drm_remove,
> >> > +	.driver		= {
> >> > +		.owner	= THIS_MODULE,
> >> > +		.name	= "fsl,dcu",
> >> > +		.pm	= &fsl_dcu_drm_pm_ops,
> >> > +		.of_match_table = fsl_dcu_of_match,
> >> > +	},
> >> > +};
> >> > +
> >> > +module_platform_driver(fsl_dcu_drm_platform_driver);
> >> > +
> >> > +MODULE_ALIAS("platform:fsl-dcu-drm");
> >> > +MODULE_DESCRIPTION("Freescale DCU DRM Driver");
> >> > +MODULE_LICENSE("GPL");
> >> > diff --git a/drivers/gpu/drm/fsl/fsl_dcu_drm_drv.h
> >> > b/drivers/gpu/drm/fsl/fsl_dcu_drm_drv.h
> >> > new file mode 100644
> >> > index 0000000..27226109
> >> > --- /dev/null
> >> > +++ b/drivers/gpu/drm/fsl/fsl_dcu_drm_drv.h
> >> > @@ -0,0 +1,210 @@
> >> > +/*
> >> > + * Copyright 2015 Freescale Semiconductor, Inc.
> >> > + *
> >> > + * Freescale DCU drm device driver
> >> > + *
> >> > + * 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 __FSL_DCU_DRM_DRV_H__
> >> > +#define __FSL_DCU_DRM_DRV_H__
> >> > +
> >> > +#include <linux/kernel.h>
> >> > +#include <linux/spinlock.h>
> >> > +#include <stddef.h>
> >> > +#include <drm/drm.h>
> >> > +#include <drm/drmP.h>
> >> > +#include <drm/drm_fb_helper.h>
> >> > +#include <drm/drm_crtc_helper.h>
> >> > +#include <drm/drm_gem_cma_helper.h>
> >> > +#include <drm/drm_fb_cma_helper.h>
> >> > +
> >> > +#include "fsl_dcu_drm_crtc.h"
> >> > +#include "fsl_dcu_drm_plane.h"
> >> > +#include "fsl_dcu_drm_connector.h"
> >> > +#define DRIVER_NAME			"fsl-dcu-drm"
> >> > +
> >> > +#define DCU_DCU_MODE			0x0010
> >> > +#define DCU_MODE_BLEND_ITER(x)		((x) << 20)
> >> > +#define DCU_MODE_RASTER_EN		BIT(14)
> >> > +#define DCU_MODE_DCU_MODE(x)		(x)
> >> > +#define DCU_MODE_DCU_MODE_MASK		0x03
> >> > +#define DCU_MODE_OFF			0
> >> > +#define DCU_MODE_NORMAL			1
> >> > +#define DCU_MODE_TEST			2
> >> > +#define DCU_MODE_COLORBAR		3
> >> > +
> >> > +#define DCU_BGND			0x0014
> >> > +#define DCU_BGND_R(x)			((x) << 16)
> >> > +#define DCU_BGND_G(x)			((x) << 8)
> >> > +#define DCU_BGND_B(x)			(x)
> >> > +
> >> > +#define DCU_DISP_SIZE			0x0018
> >> > +#define DCU_DISP_SIZE_DELTA_Y(x)	((x) << 16)
> >> > +/*Regisiter value 1/16 of horizontal resolution*/
> >> > +#define DCU_DISP_SIZE_DELTA_X(x)	((x) >> 4)
> >> > +
> >> > +#define DCU_HSYN_PARA			0x001c
> >> > +#define DCU_HSYN_PARA_BP(x)		((x) << 22)
> >> > +#define DCU_HSYN_PARA_PW(x)		((x) << 11)
> >> > +#define DCU_HSYN_PARA_FP(x)		(x)
> >> > +
> >> > +#define DCU_VSYN_PARA			0x0020
> >> > +#define DCU_VSYN_PARA_BP(x)		((x) << 22)
> >> > +#define DCU_VSYN_PARA_PW(x)		((x) << 11)
> >> > +#define DCU_VSYN_PARA_FP(x)		(x)
> >> > +
> >> > +#define DCU_SYN_POL			0x0024
> >> > +#define DCU_SYN_POL_INV_PXCK_FALL	(0 << 6)
> >> > +#define DCU_SYN_POL_NEG_REMAIN		(0 << 5)
> >> > +#define DCU_SYN_POL_INV_VS_LOW		BIT(1)
> >> > +#define DCU_SYN_POL_INV_HS_LOW		BIT(0)
> >> > +
> >> > +#define DCU_THRESHOLD			0x0028
> >> > +#define DCU_THRESHOLD_LS_BF_VS(x)	((x) << 16)
> >> > +#define DCU_THRESHOLD_OUT_BUF_HIGH(x)	((x) << 8)
> >> > +#define DCU_THRESHOLD_OUT_BUF_LOW(x)	(x)
> >> > +#define BF_VS_VAL			0x03
> >> > +#define BUF_MAX_VAL			0x78
> >> > +#define BUF_MIN_VAL			0x0a
> >> > +
> >> > +#define DCU_INT_STATUS			0x002C
> >> > +#define DCU_INT_STATUS_VSYNC		BIT(0)
> >> > +#define DCU_INT_STATUS_UNDRUN		BIT(1)
> >> > +#define DCU_INT_STATUS_LSBFVS		BIT(2)
> >> > +#define DCU_INT_STATUS_VBLANK		BIT(3)
> >> > +#define DCU_INT_STATUS_CRCREADY		BIT(4)
> >> > +#define DCU_INT_STATUS_CRCOVERFLOW	BIT(5)
> >> > +#define DCU_INT_STATUS_P1FIFOLO		BIT(6)
> >> > +#define DCU_INT_STATUS_P1FIFOHI		BIT(7)
> >> > +#define DCU_INT_STATUS_P2FIFOLO		BIT(8)
> >> > +#define DCU_INT_STATUS_P2FIFOHI		BIT(9)
> >> > +#define DCU_INT_STATUS_PROGEND		BIT(10)
> >> > +#define DCU_INT_STATUS_IPMERROR		BIT(11)
> >> > +#define DCU_INT_STATUS_LYRTRANS		BIT(12)
> >> > +#define DCU_INT_STATUS_DMATRANS		BIT(14)
> >> > +#define DCU_INT_STATUS_P3FIFOLO		BIT(16)
> >> > +#define DCU_INT_STATUS_P3FIFOHI		BIT(17)
> >> > +#define DCU_INT_STATUS_P4FIFOLO		BIT(18)
> >> > +#define DCU_INT_STATUS_P4FIFOHI		BIT(19)
> >> > +#define DCU_INT_STATUS_P1EMPTY		BIT(26)
> >> > +#define DCU_INT_STATUS_P2EMPTY		BIT(27)
> >> > +#define DCU_INT_STATUS_P3EMPTY		BIT(28)
> >> > +#define DCU_INT_STATUS_P4EMPTY		BIT(29)
> >> > +
> >> > +#define DCU_INT_MASK			0x0030
> >> > +#define DCU_INT_MASK_VSYNC		BIT(0)
> >> > +#define DCU_INT_MASK_UNDRUN		BIT(1)
> >> > +#define DCU_INT_MASK_LSBFVS		BIT(2)
> >> > +#define DCU_INT_MASK_VBLANK		BIT(3)
> >> > +#define DCU_INT_MASK_CRCREADY		BIT(4)
> >> > +#define DCU_INT_MASK_CRCOVERFLOW	BIT(5)
> >> > +#define DCU_INT_MASK_P1FIFOLO		BIT(6)
> >> > +#define DCU_INT_MASK_P1FIFOHI		BIT(7)
> >> > +#define DCU_INT_MASK_P2FIFOLO		BIT(8)
> >> > +#define DCU_INT_MASK_P2FIFOHI		BIT(9)
> >> > +#define DCU_INT_MASK_PROGEND		BIT(10)
> >> > +#define DCU_INT_MASK_IPMERROR		BIT(11)
> >> > +#define DCU_INT_MASK_LYRTRANS		BIT(12)
> >> > +#define DCU_INT_MASK_DMATRANS		BIT(14)
> >> > +#define DCU_INT_MASK_P3FIFOLO		BIT(16)
> >> > +#define DCU_INT_MASK_P3FIFOHI		BIT(17)
> >> > +#define DCU_INT_MASK_P4FIFOLO		BIT(18)
> >> > +#define DCU_INT_MASK_P4FIFOHI		BIT(19)
> >> > +#define DCU_INT_MASK_P1EMPTY		BIT(26)
> >> > +#define DCU_INT_MASK_P2EMPTY		BIT(27)
> >> > +#define DCU_INT_MASK_P3EMPTY		BIT(28)
> >> > +#define DCU_INT_MASK_P4EMPTY		BIT(29)
> >> > +
> >> > +#define DCU_DIV_RATIO			0x0054
> >> > +
> >> > +#define DCU_UPDATE_MODE			0x00cc
> >> > +#define DCU_UPDATE_MODE_MODE		BIT(31)
> >> > +#define DCU_UPDATE_MODE_READREG		BIT(30)
> >> > +
> >> > +#define DCU_DCFB_MAX			0x300
> >> > +
> >> > +#define DCU_CTRLDESCLN_1(x)		(0x200 + (x) * 0x40)
> >> > +#define DCU_CTRLDESCLN_1_HEIGHT(x)	((x) << 16)
> >> > +#define DCU_CTRLDESCLN_1_WIDTH(x)	(x)
> >> > +
> >> > +#define DCU_CTRLDESCLN_2(x)		(0x204 + (x) * 0x40)
> >> > +#define DCU_CTRLDESCLN_2_POSY(x)	((x) << 16)
> >> > +#define DCU_CTRLDESCLN_2_POSX(x)	(x)
> >> > +
> >> > +#define DCU_CTRLDESCLN_3(x)		(0x208 + (x) * 0x40)
> >> > +
> >> > +#define DCU_CTRLDESCLN_4(x)		(0x20c + (x) * 0x40)
> >> > +#define DCU_CTRLDESCLN_4_EN		BIT(31)
> >> > +#define DCU_CTRLDESCLN_4_TILE_EN	BIT(30)
> >> > +#define DCU_CTRLDESCLN_4_DATA_SEL_CLUT	BIT(29)
> >> > +#define DCU_CTRLDESCLN_4_SAFETY_EN	BIT(28)
> >> > +#define DCU_CTRLDESCLN_4_TRANS(x)	((x) << 20)
> >> > +#define DCU_CTRLDESCLN_4_BPP(x)		((x) << 16)
> >> > +#define DCU_CTRLDESCLN_4_RLE_EN		BIT(15)
> >> > +#define DCU_CTRLDESCLN_4_LUOFFS(x)	((x) << 4)
> >> > +#define DCU_CTRLDESCLN_4_BB_ON		BIT(2)
> >> > +#define DCU_CTRLDESCLN_4_AB(x)		(x)
> >> > +
> >> > +#define DCU_CTRLDESCLN_5(x)		(0x210 + (x) * 0x40)
> >> > +#define DCU_CTRLDESCLN_5_CKMAX_R(x)	((x) << 16)
> >> > +#define DCU_CTRLDESCLN_5_CKMAX_G(x)	((x) << 8)
> >> > +#define DCU_CTRLDESCLN_5_CKMAX_B(x)	(x)
> >> > +
> >> > +#define DCU_CTRLDESCLN_6(x)		(0x214 + (x) * 0x40)
> >> > +#define DCU_CTRLDESCLN_6_CKMIN_R(x)	((x) << 16)
> >> > +#define DCU_CTRLDESCLN_6_CKMIN_G(x)	((x) << 8)
> >> > +#define DCU_CTRLDESCLN_6_CKMIN_B(x)	(x)
> >> > +
> >> > +#define DCU_CTRLDESCLN_7(x)		(0x218 + (x) * 0x40)
> >> > +#define DCU_CTRLDESCLN_7_TILE_VER(x)	((x) << 16)
> >> > +#define DCU_CTRLDESCLN_7_TILE_HOR(x)	(x)
> >> > +
> >> > +#define DCU_CTRLDESCLN_8(x)		(0x21c + (x) * 0x40)
> >> > +#define DCU_CTRLDESCLN_8_FG_FCOLOR(x)	(x)
> >> > +
> >> > +#define DCU_CTRLDESCLN_9(x)		(0x220 + (x) * 0x40)
> >> > +#define DCU_CTRLDESCLN_9_BG_BCOLOR(x)	(x)
> >> > +
> >> > +#define DCU_CTRLDESCLN_10(x)		(0x224 + (x) * 0x40)
> >> > +#define DCU_CTRLDESCLN_10_POST_SKIP(x)	((x) << 16)
> >> > +#define DCU_CTRLDESCLN_10_PRE_SKIP(x)	(x)
> >> > +
> >> > +#define FSL_DCU_RGB565			4
> >> > +#define FSL_DCU_RGB888			5
> >> > +#define FSL_DCU_ARGB8888		6
> >> > +#define FSL_DCU_ARGB1555		11
> >> > +#define FSL_DCU_ARGB4444		12
> >> > +#define FSL_DCU_YUV422			14
> >> > +
> >> > +#define TCON_CTRL1			0x0000
> >> > +#define TCON_BYPASS_ENABLE		BIT(29)
> >> > +
> >> > +#define DBG(fmt, ...) DRM_DEBUG(fmt"\n", ##__VA_ARGS__)
> >> > +
> >> > +struct clk;
> >> > +struct device;
> >> > +struct drm_device;
> >> > +
> >> > +struct fsl_dcu_drm_device {
> >> > +	struct device *dev;
> >> > +	struct device_node *np;
> >> > +	struct regmap *regmap;
> >> > +	struct regmap *tcon_regmap;
> >> > +	unsigned int irq;
> >> > +	struct clk *clk;
> >> > +	/*protects hardware register*/
> >> > +	spinlock_t irq_lock;
> >> > +	struct drm_device *ddev;
> >> > +	struct drm_fbdev_cma *fbdev;
> >> > +	struct fsl_dcu_drm_crtc crtc;
> >> > +	struct drm_encoder encoder;
> >> > +	struct fsl_dcu_drm_connector connector;
> >> > +};
> >> > +
> >> > +void fsl_dcu_fbdev_init(struct drm_device *dev);
> >> > +
> >> > +#endif /* __FSL_DCU_DRM_DRV_H__ */
> >> > diff --git a/drivers/gpu/drm/fsl/fsl_dcu_drm_fbdev.c
> >> > b/drivers/gpu/drm/fsl/fsl_dcu_drm_fbdev.c
> >> > new file mode 100644
> >> > index 0000000..f8ef0e1
> >> > --- /dev/null
> >> > +++ b/drivers/gpu/drm/fsl/fsl_dcu_drm_fbdev.c
> >> > @@ -0,0 +1,26 @@
> >> > +/*
> >> > + * Copyright 2015 Freescale Semiconductor, Inc.
> >> > + *
> >> > + * 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.
> >> > + *
> >> > + * This program is distributed in the hope that it will be useful,
> but
> >> WITHOUT
> >> > + * ANY WARRANTY; without even the implied warranty of
> MERCHANTABILITY
> >> or
> >> > + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
> >> License for
> >> > + * more details.
> >> > + *
> >> > + */
> >> > +
> >> > +#include <drm/drmP.h>
> >> > +#include <drm/drm_fb_cma_helper.h>
> >> > +
> >> > +#include "fsl_dcu_drm_drv.h"
> >> > +
> >> > +/* initialize fbdev helper */
> >> > +void fsl_dcu_fbdev_init(struct drm_device *dev)
> >> > +{
> >> > +	struct fsl_dcu_drm_device *fsl_dev = dev_get_drvdata(dev->dev);
> >> > +
> >> > +	fsl_dev->fbdev = drm_fbdev_cma_init(dev, 24, 1, 1);
> >> > +}
> >> > diff --git a/drivers/gpu/drm/fsl/fsl_dcu_drm_kms.c
> >> > b/drivers/gpu/drm/fsl/fsl_dcu_drm_kms.c
> >> > new file mode 100644
> >> > index 0000000..0de21c6
> >> > --- /dev/null
> >> > +++ b/drivers/gpu/drm/fsl/fsl_dcu_drm_kms.c
> >> > @@ -0,0 +1,42 @@
> >> > +/*
> >> > + * Copyright 2015 Freescale Semiconductor, Inc.
> >> > + *
> >> > + * Freescale DCU drm device driver
> >> > + *
> >> > + * 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 "fsl_dcu_drm_crtc.h"
> >> > +#include "fsl_dcu_drm_connector.h"
> >> > +#include "fsl_dcu_drm_drv.h"
> >> > +
> >> > +static const struct drm_mode_config_funcs
> fsl_dcu_drm_mode_config_funcs
> >> = {
> >> > +	.fb_create = drm_fb_cma_create,
> >> > +	.atomic_check = drm_atomic_helper_check,
> >> > +	.atomic_commit = drm_atomic_helper_commit,
> >> > +};
> >> > +
> >> > +int fsl_dcu_drm_modeset_init(struct fsl_dcu_drm_device *fsl_dev)
> >> > +{
> >> > +	drm_mode_config_init(fsl_dev->ddev);
> >> > +
> >> > +	fsl_dev->ddev->mode_config.min_width = 0;
> >> > +	fsl_dev->ddev->mode_config.min_height = 0;
> >> > +	fsl_dev->ddev->mode_config.max_width = 2031;
> >> > +	fsl_dev->ddev->mode_config.max_height = 2047;
> >> > +	fsl_dev->ddev->mode_config.funcs =
> &fsl_dcu_drm_mode_config_funcs;
> >> > +
> >> > +	drm_kms_helper_poll_init(fsl_dev->ddev);
> >> > +	fsl_dcu_drm_crtc_create(fsl_dev);
> >> > +	fsl_dcu_drm_encoder_create(fsl_dev, &fsl_dev->crtc);
> >> > +	fsl_dcu_drm_connector_create(fsl_dev, &fsl_dev->encoder);
> >> > +	drm_mode_config_reset(fsl_dev->ddev);
> >> > +
> >> > +	return 0;
> >> > +}
> >> > diff --git a/drivers/gpu/drm/fsl/fsl_dcu_drm_kms.h
> >> > b/drivers/gpu/drm/fsl/fsl_dcu_drm_kms.h
> >> > new file mode 100644
> >> > index 0000000..b9bd299
> >> > --- /dev/null
> >> > +++ b/drivers/gpu/drm/fsl/fsl_dcu_drm_kms.h
> >> > @@ -0,0 +1,17 @@
> >> > +/*
> >> > + * Copyright 2015 Freescale Semiconductor, Inc.
> >> > + *
> >> > + * Freescale DCU drm device driver
> >> > + *
> >> > + * 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 __FSL_DCU_DRM_KMS_H__
> >> > +#define __FSL_DCU_DRM_KMS_H__
> >> > +
> >> > +int fsl_dcu_drm_modeset_init(struct fsl_dcu_drm_device *fsl_dev);
> >> > +
> >> > +#endif /* __FSL_DCU_DRM_KMS_H__ */
> >> > diff --git a/drivers/gpu/drm/fsl/fsl_dcu_drm_plane.c
> >> > b/drivers/gpu/drm/fsl/fsl_dcu_drm_plane.c
> >> > new file mode 100644
> >> > index 0000000..6146e80
> >> > --- /dev/null
> >> > +++ b/drivers/gpu/drm/fsl/fsl_dcu_drm_plane.c
> >> > @@ -0,0 +1,192 @@
> >> > +/*
> >> > + * Copyright 2015 Freescale Semiconductor, Inc.
> >> > + *
> >> > + * Freescale DCU drm device driver
> >> > + *
> >> > + * 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_crtc.h>
> >> > +#include <drm/drm_crtc_helper.h>
> >> > +#include <drm/drm_fb_cma_helper.h>
> >> > +#include <drm/drm_gem_cma_helper.h>
> >> > +#include <linux/regmap.h>
> >> > +#include <drm/drm_plane_helper.h>
> >> > +#include <drm/drm_atomic_helper.h>
> >> > +
> >> > +#include "fsl_dcu_drm_drv.h"
> >> > +#include "fsl_dcu_drm_kms.h"
> >> > +#include "fsl_dcu_drm_plane.h"
> >> > +
> >> > +#define to_fsl_dcu_plane(plane) \
> >> > +	container_of(plane, struct fsl_dcu_drm_plane, plane)
> >> > +
> >> > +static int
> >> > +fsl_dcu_drm_plane_prepare_fb(struct drm_plane *plane,
> >> > +			     struct drm_framebuffer *fb,
> >> > +			     const struct drm_plane_state *new_state)
> >> > +{
> >> > +	return 0;
> >> > +}
> >> > +
> >> > +static void
> >> > +fsl_dcu_drm_plane_cleanup_fb(struct drm_plane *plane,
> >> > +			     struct drm_framebuffer *fb,
> >> > +			     const struct drm_plane_state *new_state)
> >> > +{
> >> > +}
> >> > +
> >> > +static int fsl_dcu_drm_plane_atomic_check(struct drm_plane *plane,
> >> > +					  struct drm_plane_state *state)
> >> > +{
> >> > +	return 0;
> >> > +}
> >> > +
> >> > +static void fsl_dcu_drm_plane_atomic_disable(struct drm_plane *plane,
> >> > +					     struct drm_plane_state *old_state)
> >> > +{
> >> > +}
> >> > +
> >> > +void fsl_dcu_drm_plane_atomic_update(struct drm_plane *plane,
> >> > +				     struct drm_plane_state *old_state)
> >> > +{
> >> > +	struct fsl_dcu_drm_device *fsl_dev = plane->dev->dev_private;
> >> > +	struct drm_plane_state *state = plane->state;
> >> > +	struct drm_framebuffer *fb = plane->state->fb;
> >> > +	u32 index, alpha, bpp;
> >> > +	struct drm_gem_cma_object *gem;
> >> > +	struct fsl_dcu_drm_plane *fsl_plane = to_fsl_dcu_plane(plane);
> >> > +
> >> > +	index = fsl_plane->index;
> >> > +	gem = drm_fb_cma_get_gem_obj(fb, 0);
> >> > +
> >> > +	switch (fb->pixel_format) {
> >> > +	case DRM_FORMAT_RGB565:
> >> > +		bpp = FSL_DCU_RGB565;
> >> > +		alpha = 0xff;
> >> > +		break;
> >> > +	case DRM_FORMAT_RGB888:
> >> > +		bpp = FSL_DCU_RGB888;
> >> > +		alpha = 0xff;
> >> > +		break;
> >> > +	case DRM_FORMAT_ARGB8888:
> >> > +		bpp = FSL_DCU_ARGB8888;
> >> > +		alpha = 0xff;
> >> > +		break;
> >> > +	case DRM_FORMAT_BGRA4444:
> >> > +		bpp = FSL_DCU_ARGB4444;
> >> > +		alpha = 0xff;
> >> > +		break;
> >> > +	case DRM_FORMAT_ARGB1555:
> >> > +		bpp = FSL_DCU_ARGB1555;
> >> > +		alpha = 0xff;
> >> > +		break;
> >> > +	case DRM_FORMAT_YUV422:
> >> > +		bpp = FSL_DCU_YUV422;
> >> > +		alpha = 0xff;
> >> > +		break;
> >> > +	default:
> >> > +		return;
> >> > +	}
> >> > +
> >> > +	regmap_write(fsl_dev->regmap, DCU_CTRLDESCLN_1(index),
> >> > +		     DCU_CTRLDESCLN_1_HEIGHT(state->crtc_h) |
> >> > +		     DCU_CTRLDESCLN_1_WIDTH(state->crtc_w));
> >> > +	regmap_write(fsl_dev->regmap, DCU_CTRLDESCLN_2(index),
> >> > +		     DCU_CTRLDESCLN_2_POSY(state->crtc_y) |
> >> > +		     DCU_CTRLDESCLN_2_POSX(state->crtc_x));
> >> > +	regmap_write(fsl_dev->regmap, DCU_CTRLDESCLN_3(index), gem-
> >paddr);
> >> > +	regmap_write(fsl_dev->regmap, DCU_CTRLDESCLN_4(index),
> >> > +		     DCU_CTRLDESCLN_4_EN |
> >> > +		     DCU_CTRLDESCLN_4_TRANS(alpha) |
> >> > +		     DCU_CTRLDESCLN_4_BPP(bpp) |
> >> > +		     DCU_CTRLDESCLN_4_AB(0));
> >> > +	regmap_write(fsl_dev->regmap, DCU_CTRLDESCLN_5(index),
> >> > +		     DCU_CTRLDESCLN_5_CKMAX_R(0xFF) |
> >> > +		     DCU_CTRLDESCLN_5_CKMAX_G(0xFF) |
> >> > +		     DCU_CTRLDESCLN_5_CKMAX_B(0xFF));
> >> > +	regmap_write(fsl_dev->regmap, DCU_CTRLDESCLN_6(index),
> >> > +		     DCU_CTRLDESCLN_6_CKMIN_R(0) |
> >> > +		     DCU_CTRLDESCLN_6_CKMIN_G(0) |
> >> > +		     DCU_CTRLDESCLN_6_CKMIN_B(0));
> >> > +	regmap_write(fsl_dev->regmap, DCU_CTRLDESCLN_7(index), 0);
> >> > +	regmap_write(fsl_dev->regmap, DCU_CTRLDESCLN_8(index),
> >> > +		     DCU_CTRLDESCLN_8_FG_FCOLOR(0));
> >> > +	regmap_write(fsl_dev->regmap, DCU_CTRLDESCLN_9(index),
> >> > +		     DCU_CTRLDESCLN_9_BG_BCOLOR(0));
> >> > +	if (of_device_is_compatible(fsl_dev->np, "fsl,ls1021a-dcu"))
> >> > +		regmap_write(fsl_dev->regmap, DCU_CTRLDESCLN_10(index),
> >> > +			     DCU_CTRLDESCLN_10_POST_SKIP(0) |
> >> > +			     DCU_CTRLDESCLN_10_PRE_SKIP(0));
> >> > +	regmap_update_bits(fsl_dev->regmap, DCU_DCU_MODE,
> >> > +			   DCU_MODE_DCU_MODE_MASK,
> >> > +			   DCU_MODE_DCU_MODE(DCU_MODE_NORMAL));
> >> > +	regmap_write(fsl_dev->regmap, DCU_UPDATE_MODE,
> >> DCU_UPDATE_MODE_READREG);
> >> > +}
> >> > +
> >> > +int fsl_dcu_drm_plane_disable(struct drm_plane *plane)
> >> > +{
> >> > +	return 0;
> >> > +}
> >> > +
> >> > +void fsl_dcu_drm_plane_destroy(struct drm_plane *plane)
> >> > +{
> >> > +	fsl_dcu_drm_plane_disable(plane);
> >> > +	drm_plane_cleanup(plane);
> >> > +}
> >> > +
> >> > +static const uint32_t fsl_dcu_drm_plane_formats[] = {
> >> > +	DRM_FORMAT_RGB565,
> >> > +	DRM_FORMAT_RGB888,
> >> > +	DRM_FORMAT_ARGB8888,
> >> > +	DRM_FORMAT_ARGB4444,
> >> > +	DRM_FORMAT_ARGB1555,
> >> > +	DRM_FORMAT_YUV422,
> >> > +};
> >> > +
> >> > +static const struct drm_plane_funcs fsl_dcu_drm_plane_funcs = {
> >> > +	.update_plane = drm_atomic_helper_update_plane,
> >> > +	.disable_plane = drm_atomic_helper_disable_plane,
> >> > +	.destroy = fsl_dcu_drm_plane_destroy,
> >> > +	.atomic_duplicate_state =
> drm_atomic_helper_plane_duplicate_state,
> >> > +	.atomic_destroy_state = drm_atomic_helper_plane_destroy_state,
> >> > +	.reset = drm_atomic_helper_plane_reset,
> >> > +};
> >> > +
> >> > +static const struct drm_plane_helper_funcs
> >> fsl_dcu_drm_plane_helper_funcs = {
> >> > +	.prepare_fb = fsl_dcu_drm_plane_prepare_fb,
> >> > +	.cleanup_fb = fsl_dcu_drm_plane_cleanup_fb,
> >> > +	.atomic_check = fsl_dcu_drm_plane_atomic_check,
> >> > +	.atomic_update = fsl_dcu_drm_plane_atomic_update,
> >> > +	.atomic_disable = fsl_dcu_drm_plane_atomic_disable,
> >> > +};
> >> > +
> >> > +struct drm_plane *fsl_dcu_drm_primary_create_plane(struct drm_device
> >> *dev)
> >> > +{
> >> > +	struct drm_plane *primary;
> >> > +	int ret;
> >> > +
> >> > +	primary = kzalloc(sizeof(*primary), GFP_KERNEL);
> >> > +	if (!primary) {
> >> > +		DRM_DEBUG_KMS("Failed to allocate primary plane\n");
> >> > +		return NULL;
> >> > +	}
> >> > +
> >> > +	/* possible_crtc's will be filled in later by crtc_init */
> >> > +	ret = drm_universal_plane_init(dev, primary, 0,
> >> > +				       &fsl_dcu_drm_plane_funcs,
> >> > +				       fsl_dcu_drm_plane_formats,
> >> > +				       ARRAY_SIZE(fsl_dcu_drm_plane_formats),
> >> > +				       DRM_PLANE_TYPE_PRIMARY);
> >> > +	if (ret) {
> >> > +		kfree(primary);
> >> > +		primary = NULL;
> >> > +	}
> >> > +	drm_plane_helper_add(primary, &fsl_dcu_drm_plane_helper_funcs);
> >> > +
> >> > +	return primary;
> >> > +}
> >> > diff --git a/drivers/gpu/drm/fsl/fsl_dcu_drm_plane.h
> >> > b/drivers/gpu/drm/fsl/fsl_dcu_drm_plane.h
> >> > new file mode 100644
> >> > index 0000000..ccbfa61
> >> > --- /dev/null
> >> > +++ b/drivers/gpu/drm/fsl/fsl_dcu_drm_plane.h
> >> > @@ -0,0 +1,23 @@
> >> > +/*
> >> > + * Copyright 2015 Freescale Semiconductor, Inc.
> >> > + *
> >> > + * Freescale DCU drm device driver
> >> > + *
> >> > + * 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 __FSL_DCU_DRM_PLANE_H__
> >> > +#define __FSL_DCU_DRM_PLANE_H__
> >> > +
> >> > +struct fsl_dcu_drm_device;
> >> > +struct fsl_dcu_drm_plane {
> >> > +	struct drm_plane plane;
> >> > +	unsigned int index;
> >> > +};
> >> > +
> >> > +struct drm_plane *fsl_dcu_drm_primary_create_plane(struct drm_device
> >> *dev);
> >> > +
> >> > +#endif /* __FSL_DCU_DRM_PLANE_H__ */

--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Stefan Agner April 8, 2015, 7:57 a.m. UTC | #5
On 2015-04-08 09:17, Jianwei.Wang@freescale.com wrote:
> Hi Stefan,
> 
>> -----Original Message-----
>> From: Stefan Agner [mailto:stefan@agner.ch]
>> Sent: Tuesday, April 07, 2015 8:12 PM
>> To: Wang Jianwei-B52261
>> Cc: Wood Scott-B07421; airlied@linux.ie; dri-devel@lists.freedesktop.org;
>> devicetree@vger.kernel.org; Xiubo Li; Wang Huan-B18965; linux-
>> kernel@vger.kernel.org; Jin Zhengxiong-R64188; linux-arm-
>> kernel@lists.infradead.org
>> Subject: RE: [PATCH v3 1/4] drm/layerscape: Add Freescale DCU DRM driver
>>
>> Hi Jianwei,
>>
>> On 2015-04-07 08:44, Jianwei.Wang@freescale.com wrote:
>> > Hi Stefan,
>> >
>> > Thank you for your review and testing on Vybrid F610 device. This driver
>> > just implement the basic functions and it only support the exported
>> > framebuffer access. Some DRM interfaces are not implemented now. So your
>> > test result is normal. I will implement these interfaces with patches
>> soon
>> > afterwards. I don't plan to add new features for the initial version
>> driver,
>> > otherwise it will be a long term for this version.
>> >
>> > I tested on ls1021a using TFT panel, there are no flickers on the screen
>> > when inserting a USB HID device. I will do more test if time permits.
>> >
>> > By the way, could please give me some guidance on how X-Server use DRM
>> > Interface directly? Do you have some papers or webpage about this?
>>
>> I'm using the modesetting X.org driver. Lots of distributions ship that
>> driver as a package (e.g. xserver-xorg-video-modesetting in Debian, or
>> xf86-video-modesetting in OpenEmbedded). Since 1.17 this driver has even
>> been included into the main source tree of Xorg X-Server
>> (http://cgit.freedesktop.org/xorg/xserver/tree/hw/xfree86/drivers/modesett
>> ing)
>>
>> This driver is using KMS/DRM interface and should work well for
>> un-accelerated graphic devices. This is a a much nicer way to use X.org
>> on top of a DRM driver, since it avoids going through the legacy fbdev
>> interface. The man page shows how to use it:
>> http://linux.die.net/man/4/modesetting
>>
>> So, when the driver is installed, it is just choosing that driver in
>> xorg.conf:
>>
>> Section "Device"
>>         Identifier      "dcu"
>>         Driver          "modesetting"
>> EndSection
>>
> 
> Thank you for your guidance.
> 
>> Some more comments below...
>>
>> >
>> > My reply below...
>> >
>> >>
>> >> Hi Jianwei,
>> >>
>> >> The driver worked on a Vybrid VF610 device using the exported
>> >> framebuffer. However, when using X-Server through the DRM interface
>> >> directly (by using the modesetting driver) I get just a black screen so
>> >> far, still investigating the reason. What user-space interfaces did you
>> >> test?
>> >>
>> >> When using the FB device and insert a USB HID device, I get some
>> >> flickers on the screen. I didn't had those on the dcufb driver, did you
>> >> notice something like this too? Probably related to the resolution, I'm
>> >> using VGA resolution.
>> >>
>> >> Some comments below.
>> >>
>> >>
>> >> On 2015-03-26 06:37, Jianwei Wang wrote:
>> >> > This patch add support for Two Dimensional Animation and Compositing
>> >> > Engine (2D-ACE) on the Freescale SoCs.
>> >> >
>> >> > 2D-ACE is a Freescale display controller. 2D-ACE describes
>> >> > the functionality of the module extremely well its name is a value
>> >> > that cannot be used as a token in programming languages.
>> >> > Instead the valid token "DCU" is used to tag the register names and
>> >> > function names.
>> >> >
>> >> > The Display Controller Unit (DCU) module is a system master that
>> >> > fetches graphics stored in internal or external memory and displays
>> >> > them on a TFT LCD panel. A wide range of panel sizes is supported
>> >> > and the timing of the interface signals is highly configurable.
>> >> > Graphics are read directly from memory and then blended in real-time,
>> >> > which allows for dynamic content creation with minimal CPU
>> >> > intervention.
>> >> >
>> >> > The features:
>> >> > (1) Full RGB888 output to TFT LCD panel.
>> >> > (2) For the current LCD panel, WQVGA "480x272" is supported.
>> >> > (3) Blending of each pixel using up to 4 source layers
>> >> > dependent on size of panel.
>> >>
>> >> modetest only shows one layer currently...
>> >
>> > Yes, only one plane and one framebuffer were created now, others
>> > maybe create as user requirement or create all when initializing,
>> > I'm not sure now. This describe the hardware feature
>> >
>> >>
>> >> > (4) Each graphic layer can be placed with one pixel resolution
>> >> > in either axis.
>> >> > (5) Each graphic layer support RGB565 and RGB888 direct colors
>> >> > without alpha channel
>> >> > and BGRA8888 direct colors with an alpha channel.
>> >>
>> >> The array fsl_dcu_drm_plane_formats below shows more formats, does this
>> >> commit log needs updating?
>> >>
>> >
>> > I agree with your suggestion, I will update this commit log
>> >
>> >> > (6) Each graphic layer support alpha blending with 8-bit
>> >> > resolution.
>> >> >
>> >> > This is a simplified version, only one primary plane, one
>> >> > framebuffer created for fbdev, one crtc, one connector for
>> >> > TFT LCD panel, an encoder.
>> >> >
>> >> > Signed-off-by: Alison Wang <b18965@freescale.com>
>> >> > Signed-off-by: Xiubo Li <lixiubo@cmss.chinamobile.com>
>> >> > Signed-off-by: Jianwei Wang <b52261@freescale.com>
>> >> > ---
>> >> >
>> >> > Changed in V3:
>> >> >
>> >> > - Test driver on Vybrid board and add compatible string
>> >> > - Remove unused functions
>> >> > - set default crtc for encoder
>> >> > - replace legacy functions with atomic help functions
>> >> > - Set the unique name of the DRM device
>> >> > - Implement irq handle function for vblank interrupt
>> >> >
>> >> > Changed in v2:
>> >> > - Add atomic support
>> >> > - Modify bindings file
>> >> > - Rename node for compatibility
>> >> > - Move platform related code out for compatibility
>> >> >
>> >> >  .../devicetree/bindings/drm/fsl/fsl,dcu.txt        |  50 ++++
>> >> >  drivers/gpu/drm/Kconfig                            |   2 +
>> >> >  drivers/gpu/drm/Makefile                           |   1 +
>> >> >  drivers/gpu/drm/fsl/Kconfig                        |  17 ++
>> >> >  drivers/gpu/drm/fsl/Makefile                       |   8 +
>> >> >  drivers/gpu/drm/fsl/fsl_dcu_drm_connector.c        | 193
>> ++++++++++++
>> >> >  drivers/gpu/drm/fsl/fsl_dcu_drm_connector.h        |  30 ++
>> >> >  drivers/gpu/drm/fsl/fsl_dcu_drm_crtc.c             | 165 ++++++++++
>> >> >  drivers/gpu/drm/fsl/fsl_dcu_drm_crtc.h             |  26 ++
>> >> >  drivers/gpu/drm/fsl/fsl_dcu_drm_drv.c              | 331
>> >> +++++++++++++++++++++
>> >> >  drivers/gpu/drm/fsl/fsl_dcu_drm_drv.h              | 210
>> +++++++++++++
>> >> >  drivers/gpu/drm/fsl/fsl_dcu_drm_fbdev.c            |  26 ++
>> >> >  drivers/gpu/drm/fsl/fsl_dcu_drm_kms.c              |  42 +++
>> >> >  drivers/gpu/drm/fsl/fsl_dcu_drm_kms.h              |  17 ++
>> >> >  drivers/gpu/drm/fsl/fsl_dcu_drm_plane.c            | 192
>> ++++++++++++
>> >> >  drivers/gpu/drm/fsl/fsl_dcu_drm_plane.h            |  23 ++
>> >> >  16 files changed, 1333 insertions(+)
>> >> >  create mode 100644
>> >> Documentation/devicetree/bindings/drm/fsl/fsl,dcu.txt
>> >> >  create mode 100644 drivers/gpu/drm/fsl/Kconfig
>> >> >  create mode 100644 drivers/gpu/drm/fsl/Makefile
>> >> >  create mode 100644 drivers/gpu/drm/fsl/fsl_dcu_drm_connector.c
>> >> >  create mode 100644 drivers/gpu/drm/fsl/fsl_dcu_drm_connector.h
>> >> >  create mode 100644 drivers/gpu/drm/fsl/fsl_dcu_drm_crtc.c
>> >> >  create mode 100644 drivers/gpu/drm/fsl/fsl_dcu_drm_crtc.h
>> >> >  create mode 100644 drivers/gpu/drm/fsl/fsl_dcu_drm_drv.c
>> >> >  create mode 100644 drivers/gpu/drm/fsl/fsl_dcu_drm_drv.h
>> >> >  create mode 100644 drivers/gpu/drm/fsl/fsl_dcu_drm_fbdev.c
>> >> >  create mode 100644 drivers/gpu/drm/fsl/fsl_dcu_drm_kms.c
>> >> >  create mode 100644 drivers/gpu/drm/fsl/fsl_dcu_drm_kms.h
>> >> >  create mode 100644 drivers/gpu/drm/fsl/fsl_dcu_drm_plane.c
>> >> >  create mode 100644 drivers/gpu/drm/fsl/fsl_dcu_drm_plane.h
>> >> >
>> >> > diff --git a/Documentation/devicetree/bindings/drm/fsl/fsl,dcu.txt
>> >> > b/Documentation/devicetree/bindings/drm/fsl/fsl,dcu.txt
>> >> > new file mode 100644
>> >> > index 0000000..bdc7d5b
>> >> > --- /dev/null
>> >> > +++ b/Documentation/devicetree/bindings/drm/fsl/fsl,dcu.txt
>> >> > @@ -0,0 +1,50 @@
>> >> > +Device Tree bindings for Freescale DCU DRM Driver
>> >> > +
>> >> > +Required properties:
>> >> > +- compatible:           Should be one of
>> >> > +	* "fsl,ls1021a-dcu".
>> >> > +	* "fsl,vf610-dcu".
>> >>
>> >> In the Vybrid reference manual, that IP is denoted as "DCU4". Any
>> reason
>> >> why you left out the DCU version? Is this different for LS1021a? On the
>> >> other hand, with the SoC in the name, the IP should be specified clear
>> >> enough.
>> >>
>> >
>> > In the LS1021A reference manual, no DCU version related words. I asked
>> > previous DCU owner, she told me that LS1021A use DCU5 and she also point
>> > out that the same DCU version there may be differences between different
>> > SoCs. So I named compatible string with SoC name.
>>
>> Ok, I'm fine with that, thx for the background information.
>>
>> >
>> >> > +- reg:                  Address and length of the register set for
>> dcu.
>> >> > +- clocks:               From common clock binding: handle to dcu
>> clock.
>> >> > +- clock-names:          From common clock binding: Shall be "dcu".
>> >> > +- display:              The phandle to display node.
>> >> > +
>> >> > +Required properties:
>> >> > +- bits-per-pixel:       <16> for RGB565,
>> >> > +			<24> for RGB888,
>> >> > +			<32> for RGB8888.
>> >> > +
>> >> > +Required timing node for dispplay sub-node:
>> >> > +- display-timings:      Refer to binding doc display-timing.txt for
>> >> details.
>> >> > +
>> >> > +Examples:
>> >> > +dcu: dcu@2ce0000 {
>> >> > +	compatible = "fsl,ls1021a-dcu";
>> >> > +	reg = <0x0 0x2ce0000 0x0 0x10000>;
>> >> > +	clocks = <&platform_clk 0>;
>> >> > +	clock-names = "dcu";
>> >> > +	big-endian;
>> >> > +	display = <&display>;
>> >> > +
>> >> > +	display: display@0 {
>> >> > +		bits-per-pixel = <24>;
>> >> > +
>> >> > +		display-timings {
>> >> > +			native-mode = <&timing0>;
>> >> > +			timing0: nl4827hc19 {
>> >> > +				clock-frequency = <10870000>;
>> >> > +				hactive = <480>;
>> >> > +				vactive = <272>;
>> >> > +				hback-porch = <2>;
>> >> > +				hfront-porch = <2>;
>> >> > +				vback-porch = <1>;
>> >> > +				vfront-porch = <1>;
>> >> > +				hsync-len = <41>;
>> >> > +				vsync-len = <2>;
>> >> > +				hsync-active = <1>;
>> >> > +				vsync-active = <1>;
>> >> > +			};
>> >> > +		};
>> >> > +	};
>> >> > +};
>> >> > +
>> >> > diff --git a/drivers/gpu/drm/Kconfig b/drivers/gpu/drm/Kconfig
>> >> > index 151a050..a6957aa 100644
>> >> > --- a/drivers/gpu/drm/Kconfig
>> >> > +++ b/drivers/gpu/drm/Kconfig
>> >> > @@ -199,6 +199,8 @@ source "drivers/gpu/drm/bochs/Kconfig"
>> >> >
>> >> >  source "drivers/gpu/drm/msm/Kconfig"
>> >> >
>> >> > +source "drivers/gpu/drm/fsl/Kconfig"
>> >> > +
>> >> >  source "drivers/gpu/drm/tegra/Kconfig"
>> >> >
>> >> >  source "drivers/gpu/drm/panel/Kconfig"
>> >> > diff --git a/drivers/gpu/drm/Makefile b/drivers/gpu/drm/Makefile
>> >> > index 2c239b9..ab5b9ef 100644
>> >> > --- a/drivers/gpu/drm/Makefile
>> >> > +++ b/drivers/gpu/drm/Makefile
>> >> > @@ -56,6 +56,7 @@ obj-$(CONFIG_DRM_UDL) += udl/
>> >> >  obj-$(CONFIG_DRM_AST) += ast/
>> >> >  obj-$(CONFIG_DRM_ARMADA) += armada/
>> >> >  obj-$(CONFIG_DRM_ATMEL_HLCDC)	+= atmel-hlcdc/
>> >> > +obj-$(CONFIG_DRM_FSL_DCU) += fsl/
>> >>
>> >> Hm, I'm wondering whether it would be a good idea to store that driver
>> >> under fsl-dcu/... Any opinion?
>> >>
>> >
>> > I think it is good advice, I'll think about this
>> >
>> >> >  obj-$(CONFIG_DRM_RCAR_DU) += rcar-du/
>> >> >  obj-$(CONFIG_DRM_SHMOBILE) +=shmobile/
>> >> >  obj-$(CONFIG_DRM_OMAP)	+= omapdrm/
>> >> > diff --git a/drivers/gpu/drm/fsl/Kconfig
>> b/drivers/gpu/drm/fsl/Kconfig
>> >> > new file mode 100644
>> >> > index 0000000..e4f8df0
>> >> > --- /dev/null
>> >> > +++ b/drivers/gpu/drm/fsl/Kconfig
>> >> > @@ -0,0 +1,17 @@
>> >> > +config DRM_FSL_DCU
>> >> > +	tristate "DRM Support for Freescale DCU"
>> >> > +	depends on DRM && OF && ARM
>> >> > +	select DRM_KMS_HELPER
>> >> > +	select DRM_KMS_CMA_HELPER
>> >> > +	select VIDEOMODE_HELPERS
>> >> > +	select BACKLIGHT_CLASS_DEVICE
>> >> > +	select BACKLIGHT_LCD_SUPPORT
>> >> > +	select REGMAP_MMIO
>> >> > +	select DRM_KMS_FB_HELPER
>> >> > +	select FB_SYS_FILLRECT
>> >> > +	select FB_SYS_COPYAREA
>> >> > +	select FB_SYS_IMAGEBLIT
>> >> > +	select FB_SYS_FOPS
>> >> > +	help
>> >> > +	  Choose this option if you have an Freescale DCU chipset.
>> >> > +	  If M is selected the module will be called fsl-dcu-drm.
>> >> > diff --git a/drivers/gpu/drm/fsl/Makefile
>> b/drivers/gpu/drm/fsl/Makefile
>> >> > new file mode 100644
>> >> > index 0000000..5f74aee
>> >> > --- /dev/null
>> >> > +++ b/drivers/gpu/drm/fsl/Makefile
>> >> > @@ -0,0 +1,8 @@
>> >> > +fsl-dcu-drm-y := fsl_dcu_drm_drv.o \
>> >> > +	       fsl_dcu_drm_kms.o \
>> >> > +	       fsl_dcu_drm_connector.o \
>> >> > +	       fsl_dcu_drm_plane.o \
>> >> > +	       fsl_dcu_drm_crtc.o \
>> >> > +	       fsl_dcu_drm_fbdev.o \
>> >> > +
>> >> > +obj-$(CONFIG_DRM_FSL_DCU)	+= fsl-dcu-drm.o
>> >> > diff --git a/drivers/gpu/drm/fsl/fsl_dcu_drm_connector.c
>> >> > b/drivers/gpu/drm/fsl/fsl_dcu_drm_connector.c
>> >> > new file mode 100644
>> >> > index 0000000..4610647
>> >> > --- /dev/null
>> >> > +++ b/drivers/gpu/drm/fsl/fsl_dcu_drm_connector.c
>> >> > @@ -0,0 +1,193 @@
>> >> > +/*
>> >> > + * Copyright 2015 Freescale Semiconductor, Inc.
>> >> > + *
>> >> > + * Freescale DCU drm device driver
>> >> > + *
>> >> > + * This program is free software; you can redistribute it and/or
>> modify
>> >> > + * it under the terms of the GNU General Public License as published
>> by
>> >> > + * the Free Software Foundation; either version 2 of the License, or
>> >> > + * (at your option) any later version.
>> >> > + */
>> >> > +
>> >> > +#include <linux/backlight.h>
>> >> > +
>> >> > +#include <drm/drmP.h>
>> >> > +#include <drm/drm_atomic_helper.h>
>> >> > +#include <video/of_display_timing.h>
>> >> > +
>> >> > +#include "fsl_dcu_drm_drv.h"
>> >> > +#include "fsl_dcu_drm_connector.h"
>> >> > +
>> >> > +static void fsl_dcu_drm_encoder_dpms(struct drm_encoder *encoder,
>> int
>> >> mode)
>> >> > +{
>> >> > +}
>> >> > +
>> >> > +static void fsl_dcu_drm_encoder_mode_prepare(struct drm_encoder
>> >> *encoder)
>> >> > +{
>> >> > +}
>> >> > +
>> >> > +static void fsl_dcu_drm_encoder_mode_set(struct drm_encoder *encoder,
>> >> > +					 struct drm_display_mode *mode,
>> >> > +					 struct drm_display_mode
>> *adjusted_mode)
>> >> > +{
>> >> > +}
>> >> > +
>> >> > +static void fsl_dcu_drm_encoder_mode_commit(struct drm_encoder
>> *encoder)
>> >> > +{
>> >> > +}
>> >> > +
>> >> > +static void fsl_dcu_drm_encoder_disable(struct drm_encoder *encoder)
>> >> > +{
>> >> > +}
>> >> > +
>> >> > +static int
>> >> > +fsl_dcu_drm_encoder_atomic_check(struct drm_encoder *encoder,
>> >> > +				 struct drm_crtc_state *crtc_state,
>> >> > +				 struct drm_connector_state *conn_state)
>> >> > +{
>> >> > +	return 0;
>> >> > +}
>> >> > +
>> >> > +static void fsl_dcu_drm_encoder_destroy(struct drm_encoder *encoder)
>> >> > +{
>> >> > +	drm_encoder_cleanup(encoder);
>> >> > +}
>> >> > +
>> >> > +static const struct drm_encoder_helper_funcs encoder_helper_funcs =
>> {
>> >> > +	.dpms = fsl_dcu_drm_encoder_dpms,
>> >> > +	.prepare = fsl_dcu_drm_encoder_mode_prepare,
>> >> > +	.commit = fsl_dcu_drm_encoder_mode_commit,
>> >> > +	.mode_set = fsl_dcu_drm_encoder_mode_set,
>> >> > +	.disable = fsl_dcu_drm_encoder_disable,
>> >> > +	.atomic_check = fsl_dcu_drm_encoder_atomic_check,
>> >> > +};
>> >> > +
>> >> > +static const struct drm_encoder_funcs encoder_funcs = {
>> >> > +	.destroy = fsl_dcu_drm_encoder_destroy,
>> >> > +};
>> >> > +
>> >> > +int fsl_dcu_drm_encoder_create(struct fsl_dcu_drm_device *fsl_dev,
>> >> > +			       struct fsl_dcu_drm_crtc *crtc)
>> >> > +{
>> >> > +	struct drm_encoder *encoder = &fsl_dev->encoder;
>> >> > +	int ret;
>> >> > +
>> >> > +	ret = drm_encoder_init(fsl_dev->ddev, encoder, &encoder_funcs,
>> >> > +			       DRM_MODE_ENCODER_LVDS);
>> >> > +	if (ret < 0)
>> >> > +		return ret;
>> >> > +
>> >> > +	drm_encoder_helper_add(encoder, &encoder_helper_funcs);
>> >> > +	encoder->crtc = &crtc->crtc;
>> >> > +
>> >> > +	return 0;
>> >> > +}
>> >> > +
>> >> > +#define to_fsl_dcu_connector(connector) \
>> >> > +	container_of(connector, struct fsl_dcu_drm_connector,
>> connector)
>> >> > +
>> >> > +static int fsl_dcu_drm_connector_get_modes(struct drm_connector
>> >> *connector)
>> >> > +{
>> >> > +	struct drm_device *dev = connector->dev;
>> >> > +	struct device_node *display_np, *np = dev->dev->of_node;
>> >> > +	struct drm_display_mode *mode = drm_mode_create(connector-
>> >dev);
>> >> > +	int num_modes = 0;
>> >> > +
>> >> > +	if (np) {
>> >> > +		display_np = of_parse_phandle(np, "display", 0);
>> >> > +		if (!display_np) {
>> >> > +			dev_err(dev->dev, "failed to find display
>> phandle\n");
>> >> > +			return num_modes;
>> >> > +		}
>> >> > +		of_get_drm_display_mode(display_np, mode,
>> OF_USE_NATIVE_MODE);
>> >> > +		mode->type |= DRM_MODE_TYPE_DRIVER |
>> DRM_MODE_TYPE_PREFERRED,
>> >> > +		drm_mode_probed_add(connector, mode);
>> >> > +		num_modes++;
>> >> > +	}
>> >> > +
>> >> > +	return num_modes;
>> >> > +}
>> >> > +
>> >> > +static int fsl_dcu_drm_connector_mode_valid(struct drm_connector
>> >> *connector,
>> >> > +					    struct drm_display_mode *mode)
>> >> > +{
>> >> > +	return MODE_OK;
>> >> > +}
>> >> > +
>> >> > +static struct drm_encoder *
>> >> > +fsl_dcu_drm_connector_best_encoder(struct drm_connector *connector)
>> >> > +{
>> >> > +	struct fsl_dcu_drm_connector *fsl_con =
>> >> to_fsl_dcu_connector(connector);
>> >> > +
>> >> > +	return fsl_con->encoder;
>> >> > +}
>> >> > +
>> >> > +static void fsl_dcu_drm_connector_destroy(struct drm_connector
>> >> *connector)
>> >> > +{
>> >> > +	drm_connector_unregister(connector);
>> >> > +	drm_connector_cleanup(connector);
>> >> > +}
>> >> > +
>> >> > +static enum drm_connector_status
>> >> > +fsl_dcu_drm_connector_detect(struct drm_connector *connector, bool
>> >> force)
>> >> > +{
>> >> > +	return connector_status_connected;
>> >> > +}
>> >> > +
>> >> > +static const struct drm_connector_funcs fsl_dcu_drm_connector_funcs
>> = {
>> >> > +	.dpms = drm_atomic_helper_connector_dpms,
>> >> > +	.reset = drm_atomic_helper_connector_reset,
>> >> > +	.detect = fsl_dcu_drm_connector_detect,
>> >> > +	.fill_modes = drm_helper_probe_single_connector_modes,
>> >> > +	.destroy = fsl_dcu_drm_connector_destroy,
>> >> > +	.atomic_duplicate_state =
>> >> drm_atomic_helper_connector_duplicate_state,
>> >> > +	.atomic_destroy_state =
>> drm_atomic_helper_connector_destroy_state,
>> >> > +};
>> >> > +
>> >> > +static const struct drm_connector_helper_funcs
>> connector_helper_funcs =
>> >> {
>> >> > +	.get_modes = fsl_dcu_drm_connector_get_modes,
>> >> > +	.mode_valid = fsl_dcu_drm_connector_mode_valid,
>> >> > +	.best_encoder = fsl_dcu_drm_connector_best_encoder,
>> >> > +};
>> >> > +
>> >> > +int fsl_dcu_drm_connector_create(struct fsl_dcu_drm_device *fsl_dev,
>> >> > +				 struct drm_encoder *encoder)
>> >> > +{
>> >> > +	struct drm_connector *connector = &fsl_dev-
>> >connector.connector;
>> >> > +	int ret;
>> >> > +
>> >> > +	fsl_dev->connector.encoder = encoder;
>> >> > +
>> >> > +	connector->display_info.width_mm = 0;
>> >> > +	connector->display_info.height_mm = 0;
>> >> > +
>> >> > +	ret = drm_connector_init(fsl_dev->ddev, connector,
>> >> > +				 &fsl_dcu_drm_connector_funcs,
>> >> > +				 DRM_MODE_CONNECTOR_LVDS);
>> >> > +	if (ret < 0)
>> >> > +		return ret;
>> >> > +
>> >> > +	connector->dpms = DRM_MODE_DPMS_OFF;
>> >> > +	drm_connector_helper_add(connector, &connector_helper_funcs);
>> >> > +	ret = drm_connector_register(connector);
>> >> > +	if (ret < 0)
>> >> > +		goto err_cleanup;
>> >> > +
>> >> > +	ret = drm_mode_connector_attach_encoder(connector, encoder);
>> >> > +	if (ret < 0)
>> >> > +		goto err_sysfs;
>> >> > +
>> >> > +	connector->encoder = encoder;
>> >> > +
>> >> > +	drm_object_property_set_value
>> >> > +		(&connector->base, fsl_dev->ddev-
>> >mode_config.dpms_property,
>> >> > +		DRM_MODE_DPMS_OFF);
>> >> > +
>> >> > +	return 0;
>> >> > +
>> >> > +err_sysfs:
>> >> > +	drm_connector_unregister(connector);
>> >> > +err_cleanup:
>> >> > +	drm_connector_cleanup(connector);
>> >> > +	return ret;
>> >> > +}
>> >> > diff --git a/drivers/gpu/drm/fsl/fsl_dcu_drm_connector.h
>> >> > b/drivers/gpu/drm/fsl/fsl_dcu_drm_connector.h
>> >> > new file mode 100644
>> >> > index 0000000..bbf6d38
>> >> > --- /dev/null
>> >> > +++ b/drivers/gpu/drm/fsl/fsl_dcu_drm_connector.h
>> >> > @@ -0,0 +1,30 @@
>> >> > +/*
>> >> > + * Copyright 2015 Freescale Semiconductor, Inc.
>> >> > + *
>> >> > + * Freescale DCU drm device driver
>> >> > + *
>> >> > + * 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 __FSL_DCU_DRM_CONNECTOR_H__
>> >> > +#define __FSL_DCU_DRM_CONNECTOR_H__
>> >> > +
>> >> > +#include <drm/drmP.h>
>> >> > +#include <drm/drm_crtc.h>
>> >> > +#include "fsl_dcu_drm_crtc.h"
>> >> > +
>> >> > +struct fsl_dcu_drm_device;
>> >> > +struct fsl_dcu_drm_connector {
>> >> > +	struct drm_connector connector;
>> >> > +	struct drm_encoder *encoder;
>> >> > +};
>> >> > +
>> >> > +int fsl_dcu_drm_encoder_create(struct fsl_dcu_drm_device *fsl_dev,
>> >> > +			       struct fsl_dcu_drm_crtc *crtc);
>> >> > +int fsl_dcu_drm_connector_create(struct fsl_dcu_drm_device *fsl_dev,
>> >> > +				 struct drm_encoder *encoder);
>> >> > +
>> >> > +#endif /* __FSL_DCU_DRM_CONNECTOR_H__ */
>> >> > diff --git a/drivers/gpu/drm/fsl/fsl_dcu_drm_crtc.c
>> >> > b/drivers/gpu/drm/fsl/fsl_dcu_drm_crtc.c
>> >> > new file mode 100644
>> >> > index 0000000..076e273
>> >> > --- /dev/null
>> >> > +++ b/drivers/gpu/drm/fsl/fsl_dcu_drm_crtc.c
>> >> > @@ -0,0 +1,165 @@
>> >> > +/*
>> >> > + * Copyright 2015 Freescale Semiconductor, Inc.
>> >> > + *
>> >> > + * Freescale DCU drm device driver
>> >> > + *
>> >> > + * This program is free software; you can redistribute it and/or
>> modify
>> >> > + * it under the terms of the GNU General Public License as published
>> by
>> >> > + * the Free Software Foundation; either version 2 of the License, or
>> >> > + * (at your option) any later version.
>> >> > + */
>> >> > +
>> >> > +#include <linux/regmap.h>
>> >> > +#include <linux/clk.h>
>> >> > +
>> >> > +#include <drm/drmP.h>
>> >> > +#include <drm/drm_atomic.h>
>> >> > +#include <drm/drm_atomic_helper.h>
>> >> > +#include <drm/drm_crtc.h>
>> >> > +
>> >> > +#include "fsl_dcu_drm_crtc.h"
>> >> > +#include "fsl_dcu_drm_drv.h"
>> >> > +#include "fsl_dcu_drm_plane.h"
>> >> > +
>> >> > +#define to_fsl_dcu_crtc(c)	container_of(c, struct
>> fsl_dcu_drm_crtc,
>> >> crtc)
>> >> > +
>> >> > +void fsl_dcu_drm_crtc_suspend(struct drm_crtc *crtc)
>> >> > +{
>> >> > +}
>> >> > +
>> >> > +static void fsl_dcu_drm_crtc_mode_set_nofb(struct drm_crtc *crtc)
>> >> > +{
>> >> > +	struct drm_device *dev = crtc->dev;
>> >> > +	struct fsl_dcu_drm_device *fsl_dev = dev->dev_private;
>> >> > +	struct drm_display_mode *mode = &crtc->state->mode;
>> >> > +	uint32_t hbp, hfp, hsw, vbp, vfp, vsw, div, index;
>> >> > +
>> >> > +	DBG(": set mode: %d:\"%s\" %d %d %d %d %d %d %d %d %d %d 0x%x
>> 0x%x",
>> >> > +	    mode->base.id, mode->name,
>> >> > +	    mode->vrefresh, mode->clock,
>> >> > +	    mode->hdisplay, mode->hsync_start,
>> >> > +	    mode->hsync_end, mode->htotal,
>> >> > +	    mode->vdisplay, mode->vsync_start,
>> >> > +	    mode->vsync_end, mode->vtotal,
>> >> > +	    mode->type, mode->flags);
>> >> > +
>> >> > +	index = drm_crtc_index(crtc);
>> >> > +	div = (uint32_t)clk_get_rate(fsl_dev->clk) / mode->clock /
>> 1000;
>> >> > +
>> >> > +	/* Configure timings: */
>> >> > +	hbp = mode->htotal - mode->hsync_end;
>> >> > +	hfp = mode->hsync_start - mode->hdisplay;
>> >> > +	hsw = mode->hsync_end - mode->hsync_start;
>> >> > +	vbp = mode->vtotal - mode->vsync_end;
>> >> > +	vfp = mode->vsync_start - mode->vdisplay;
>> >> > +	vsw = mode->vsync_end - mode->vsync_start;
>> >> > +
>> >> > +	regmap_write(fsl_dev->regmap, DCU_HSYN_PARA,
>> >> > +		     DCU_HSYN_PARA_BP(hbp) |
>> >> > +		     DCU_HSYN_PARA_PW(hsw) |
>> >> > +		     DCU_HSYN_PARA_FP(hfp));
>> >> > +	regmap_write(fsl_dev->regmap, DCU_VSYN_PARA,
>> >> > +		     DCU_VSYN_PARA_BP(vbp) |
>> >> > +		     DCU_VSYN_PARA_PW(vsw) |
>> >> > +		     DCU_VSYN_PARA_FP(vfp));
>> >> > +	regmap_write(fsl_dev->regmap, DCU_DISP_SIZE,
>> >> > +		     DCU_DISP_SIZE_DELTA_Y(mode->vdisplay) |
>> >> > +		     DCU_DISP_SIZE_DELTA_X(mode->hdisplay));
>> >> > +	regmap_write(fsl_dev->regmap, DCU_DIV_RATIO, div);
>> >> > +	regmap_write(fsl_dev->regmap, DCU_UPDATE_MODE,
>> >> DCU_UPDATE_MODE_READREG);
>> >> > +}
>> >> > +
>> >> > +static bool fsl_dcu_drm_crtc_mode_fixup(struct drm_crtc *crtc,
>> >> > +					const struct drm_display_mode *mode,
>> >> > +					struct drm_display_mode *adjusted_mode)
>> >> > +{
>> >> > +	return true;
>> >> > +}
>> >> > +
>> >> > +static void fsl_dcu_drm_crtc_prepare(struct drm_crtc *crtc)
>> >> > +{
>> >> > +}
>> >> > +
>> >> > +/* Now enable the clocks, plane, pipe, and connectors that we set up.
>> >> */
>> >> > +static void fsl_dcu_drm_crtc_mode_commit(struct drm_crtc *crtc)
>> >> > +{
>> >> > +}
>> >> > +
>> >> > +static int fsl_dcu_drm_crtc_atomic_check(struct drm_crtc *crtc,
>> >> > +					 struct drm_crtc_state *state)
>> >> > +{
>> >> > +	return 0;
>> >> > +}
>> >> > +
>> >> > +static void fsl_dcu_drm_crtc_atomic_begin(struct drm_crtc *crtc)
>> >> > +{
>> >> > +}
>> >> > +
>> >> > +static void fsl_dcu_drm_crtc_atomic_flush(struct drm_crtc *crtc)
>> >> > +{
>> >> > +}
>> >> > +
>> >> > +static void fsl_dcu_drm_disable_crtc(struct drm_crtc *crtc)
>> >> > +{
>> >> > +}
>> >> > +
>> >> > +static const struct drm_crtc_funcs fsl_dcu_drm_crtc_funcs = {
>> >> > +	.page_flip = drm_atomic_helper_page_flip,
>> >> > +	.set_config = drm_atomic_helper_set_config,
>> >> > +	.destroy = drm_crtc_cleanup,
>> >> > +	.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 void fsl_dcu_drm_crtc_dpms(struct drm_crtc *crtc, int mode)
>> >> > +{
>> >> > +}
>> >> > +
>> >> > +static const struct drm_crtc_helper_funcs
>> fsl_dcu_drm_crtc_helper_funcs
>> >> = {
>> >> > +	.disable = fsl_dcu_drm_disable_crtc,
>> >> > +	.mode_fixup = fsl_dcu_drm_crtc_mode_fixup,
>> >> > +	.mode_set = drm_helper_crtc_mode_set,
>> >> > +	.mode_set_nofb = fsl_dcu_drm_crtc_mode_set_nofb,
>> >> > +	.mode_set_base = drm_helper_crtc_mode_set_base,
>> >> > +	.prepare = fsl_dcu_drm_crtc_prepare,
>> >> > +	.commit = fsl_dcu_drm_crtc_mode_commit,
>> >> > +	.atomic_check = fsl_dcu_drm_crtc_atomic_check,
>> >> > +	.atomic_begin = fsl_dcu_drm_crtc_atomic_begin,
>> >> > +	.atomic_flush = fsl_dcu_drm_crtc_atomic_flush,
>> >> > +	.dpms = fsl_dcu_drm_crtc_dpms,
>> >> > +};
>> >> > +
>> >> > +int fsl_dcu_drm_crtc_create(struct fsl_dcu_drm_device *fsl_dev)
>> >> > +{
>> >> > +	struct drm_plane *primary;
>> >> > +	struct drm_crtc *crtc = &fsl_dev->crtc.crtc;
>> >> > +	int ret;
>> >> > +
>>
>>
>> I hit an issue on some Vybrid devices because the planes have not been
>> properly initialized. It seems that initialization of planes is required
>> for Vybrid, something like this was also part of the DCU fbdev driver
>> submitted by Alison Wang:
>>
>> +#define DCU_TOTAL_LAYER_NUM    64
>>  int fsl_dcu_drm_crtc_create(struct fsl_dcu_drm_device *fsl_dev)
>>  {
>>         struct drm_plane *primary;
>>         struct drm_crtc *crtc = &fsl_dev->crtc.crtc;
>>         int ret;
>> +       int i;
>> +
>> +       for (i = 1; i < DCU_TOTAL_LAYER_NUM; i++) {
>> +               regmap_write(fsl_dev->regmap, DCU_CTRLDESCLN_1(i), 0);
>> +               regmap_write(fsl_dev->regmap, DCU_CTRLDESCLN_2(i), 0);
>> +               regmap_write(fsl_dev->regmap, DCU_CTRLDESCLN_3(i), 0);
>> +               regmap_write(fsl_dev->regmap, DCU_CTRLDESCLN_4(i), 0);
>> +               regmap_write(fsl_dev->regmap, DCU_CTRLDESCLN_5(i), 0);
>> +               regmap_write(fsl_dev->regmap, DCU_CTRLDESCLN_6(i), 0);
>> +               regmap_write(fsl_dev->regmap, DCU_CTRLDESCLN_7(i), 0);
>> +               regmap_write(fsl_dev->regmap, DCU_CTRLDESCLN_8(i), 0);
>> +               regmap_write(fsl_dev->regmap, DCU_CTRLDESCLN_9(i), 0);
>> +       }
>> +       regmap_write(fsl_dev->regmap, DCU_UPDATE_MODE,
>> DCU_UPDATE_MODE_READREG);
>>
>>         fsl_dev->crtc.dpms = DRM_MODE_DPMS_OFF;
>>
>>
>> Not sure if this is required for ls1021a too...
>>
> 
> I have tested that there is no influence on ls1021a whether doing this
> initialization.
> If it is a mast for Vybrid device, I will add layers initialization.

Thanks for including this, really appreciated.

There is nothing specified in the RM, but I found this Technical
Overview slide deck:
http://www.freescale.com/files/training/doc/dwf/DWF13_AMF_IND_T0847.pdf

Slide 58 states that the layers are not initialized. Also, the fb driver
did the same, and the Kernel crashes on some hardware without this
initialization, hence I guess for Vybrid its really required.

If it is not needed for LS1021a, you could also make it conditional for
the Vybrid compatibility string.

> 
>>
>> >> > +	fsl_dev->crtc.dpms = DRM_MODE_DPMS_OFF;
>> >> > +
>> >> > +	primary = fsl_dcu_drm_primary_create_plane(fsl_dev->ddev);
>> >> > +	ret = drm_crtc_init_with_planes(fsl_dev->ddev, crtc, primary,
>> NULL,
>> >> > +					&fsl_dcu_drm_crtc_funcs);
>> >> > +	if (ret < 0)
>> >> > +		return ret;
>> >> > +
>> >> > +	drm_crtc_helper_add(crtc, &fsl_dcu_drm_crtc_helper_funcs);
>> >> > +
>> >> > +	regmap_write(fsl_dev->regmap, DCU_SYN_POL,
>> >> > +		     DCU_SYN_POL_INV_VS_LOW | DCU_SYN_POL_INV_HS_LOW);
>> >> > +	regmap_write(fsl_dev->regmap, DCU_BGND, DCU_BGND_R(0) |
>> >> > +		     DCU_BGND_G(0) | DCU_BGND_B(0));
>> >> > +	regmap_write(fsl_dev->regmap, DCU_DCU_MODE,
>> >> > +		     DCU_MODE_BLEND_ITER(1) | DCU_MODE_RASTER_EN);
>> >> > +	regmap_write(fsl_dev->regmap, DCU_THRESHOLD,
>> >> > +		     DCU_THRESHOLD_LS_BF_VS(BF_VS_VAL) |
>> >> > +		     DCU_THRESHOLD_OUT_BUF_HIGH(BUF_MAX_VAL) |
>> >> > +		     DCU_THRESHOLD_OUT_BUF_LOW(BUF_MIN_VAL));
>> >> > +	regmap_update_bits(fsl_dev->regmap, DCU_DCU_MODE,
>> >> > +			   DCU_MODE_DCU_MODE_MASK,
>> >> > +			   DCU_MODE_DCU_MODE(DCU_MODE_OFF));
>> >> > +	regmap_write(fsl_dev->regmap, DCU_UPDATE_MODE,
>> >> DCU_UPDATE_MODE_READREG);
>> >> > +
>> >> > +	return 0;
>> >> > +}
>> >> > diff --git a/drivers/gpu/drm/fsl/fsl_dcu_drm_crtc.h
>> >> > b/drivers/gpu/drm/fsl/fsl_dcu_drm_crtc.h
>> >> > new file mode 100644
>> >> > index 0000000..d44b564
>> >> > --- /dev/null
>> >> > +++ b/drivers/gpu/drm/fsl/fsl_dcu_drm_crtc.h
>> >> > @@ -0,0 +1,26 @@
>> >> > +/*
>> >> > + * Copyright 2015 Freescale Semiconductor, Inc.
>> >> > + *
>> >> > + * Freescale DCU drm device driver
>> >> > + *
>> >> > + * 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 __FSL_DCU_DRM_CRTC_H__
>> >> > +#define __FSL_DCU_DRM_CRTC_H__
>> >> > +
>> >> > +#include <drm/drmP.h>
>> >> > +#include <drm/drm_crtc.h>
>> >> > +
>> >> > +struct fsl_dcu_drm_device;
>> >> > +struct fsl_dcu_drm_crtc {
>> >> > +	struct drm_crtc crtc;
>> >> > +	int dpms;
>> >> > +};
>> >> > +
>> >> > +int fsl_dcu_drm_crtc_create(struct fsl_dcu_drm_device *fsl_dev);
>> >> > +
>> >> > +#endif /* __FSL_DCU_DRM_CRTC_H__ */
>> >> > diff --git a/drivers/gpu/drm/fsl/fsl_dcu_drm_drv.c
>> >> > b/drivers/gpu/drm/fsl/fsl_dcu_drm_drv.c
>> >> > new file mode 100644
>> >> > index 0000000..d4a559a
>> >> > --- /dev/null
>> >> > +++ b/drivers/gpu/drm/fsl/fsl_dcu_drm_drv.c
>> >> > @@ -0,0 +1,331 @@
>> >> > +/*
>> >> > + * Copyright 2015 Freescale Semiconductor, Inc.
>> >> > + *
>> >> > + * Freescale DCU drm device driver
>> >> > + *
>> >> > + * This program is free software; you can redistribute it and/or
>> modify
>> >> > + * it under the terms of the GNU General Public License as published
>> by
>> >> > + * the Free Software Foundation; either version 2 of the License, or
>> >> > + * (at your option) any later version.
>> >> > + */
>> >> > +
>> >> > +#include <linux/clk.h>
>> >> > +#include <linux/io.h>
>> >> > +#include <linux/mm.h>
>> >> > +#include <linux/module.h>
>> >> > +#include <linux/of_platform.h>
>> >> > +#include <linux/platform_device.h>
>> >> > +#include <linux/pm.h>
>> >> > +#include <linux/pm_runtime.h>
>> >> > +#include <linux/regmap.h>
>> >> > +
>> >> > +#include <drm/drmP.h>
>> >> > +#include <linux/fsl/dcu.h>
>> >>
>> >> This file seems to be missing in that patch.
>> >>
>> >
>> > This file in patch 2/4, It's LS1021A platform related code.
>> >
>>
>> This is not allowed in the kernel world: Each commit need to represent a
>> complete change in the sense of being compileable and runnable. This is
>> required to bisect kernel issues. Git bisect helps isolate issues by
>> selecting random commits. If someone is using git bisect, and git
>> happens to choose to test this exact revision, the developer will sit in
>> front of a broken kernel. Whenever possible, we try to avoid that.
>>
>> In this case, you can easily avoid that by moving patch 2/4 in front of
>> this patch. Then the file will be there when the driver is using it.
>>
> 
> I will adjust the sequence properly. Thank you again, I learn a lot from you.
> 
>> However, as I already stated in v2 of the patchset, I don't think that
>> direct calls into arch are the right solution to enable the pixel clock.
>> To me, that looks like a clock gate which asks for the common clock
>> framework being used, e.g. the clk-gate driver:
>> http://lxr.free-electrons.com/source/drivers/clk/clk-gate.c
>>
>> The DCU clock gates in Vybrid use this driver too, see:
>> http://lxr.free-electrons.com/source/arch/arm/mach-imx/clk-vf610.c#L317
>>
>> --
>> Stefan
>>
> 
> Hum... I think this clock may not as you considered. This clock is pixel clock
> rather than DCU module clock. Enable it means allow the clock export
> to the pixel pin
> from DCU module. Common clock framework isn't suitable for managing this clock.

The common clock framework slide deck of Free Electrons explicitly
state:
..."Controlling clocks is useful for:" ... "time reference: to compute a
baud-rate or a pixel clock for
example".
http://elinux.org/images/b/b8/Elc2013_Clement.pdf

I think the common clock framework is perfectly fine for this use case.
You can also assign two clocks to a module, and use something like:

clocks = <&platform_clk 0>, <&scfg_clk DCU0_PIXELCLOCK>;
clock-names = "ipg", "pixclk;

The IPU of i.MX6 also uses the clock framework to get the pixel clocks
assigned:
http://lxr.free-electrons.com/source/arch/arm/boot/dts/imx6q.dtsi#L154

You probably need to introduce something like clk-ls102xa.c, and export
the clocks available from the scfg module...

--
Stefan


> 
> --
> Jianwei
>>
>> >> > +
>> >> > +#include "fsl_dcu_drm_drv.h"
>> >> > +#include "fsl_dcu_drm_kms.h"
>> >> > +
>> >> > +static int fsl_dcu_unload(struct drm_device *dev)
>> >> > +{
>> >> > +	drm_mode_config_cleanup(dev);
>> >> > +	drm_vblank_cleanup(dev);
>> >> > +	drm_irq_uninstall(dev);
>> >> > +
>> >> > +	dev->dev_private = NULL;
>> >> > +
>> >> > +	return 0;
>> >> > +}
>> >> > +
>> >> > +static struct regmap_config fsl_dcu_regmap_config = {
>> >> > +	.reg_bits = 32,
>> >> > +	.reg_stride = 4,
>> >> > +	.val_bits = 32,
>> >> > +};
>> >> > +
>> >> > +static int fsl_dcu_bypass_tcon(struct fsl_dcu_drm_device *fsl_dev,
>> >> > +			       struct device_node *np)
>> >> > +{
>> >> > +	struct device_node *tcon_np;
>> >> > +	struct platform_device *pdev;
>> >> > +	struct clk *tcon_clk;
>> >> > +	struct resource *res;
>> >> > +	void __iomem *base;
>> >> > +
>> >> > +	tcon_np = of_parse_phandle(np, "tcon-controller", 0);
>> >> > +	if (!tcon_np)
>> >> > +		return -EINVAL;
>> >> > +
>> >> > +	pdev = of_find_device_by_node(tcon_np);
>> >> > +	if (!pdev)
>> >> > +		return -EINVAL;
>> >> > +
>> >> > +	tcon_clk = devm_clk_get(&pdev->dev, "tcon");
>> >> > +	if (IS_ERR(tcon_clk))
>> >> > +		return PTR_ERR(tcon_clk);
>> >> > +	clk_prepare_enable(tcon_clk);
>> >>
>> >> You enable the clock explicitly...
>> >>
>> >> > +
>> >> > +	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
>> >> > +	if (!res)
>> >> > +		return -ENODEV;
>> >> > +
>> >> > +	base = devm_ioremap_resource(&pdev->dev, res);
>> >> > +	if (IS_ERR(base))
>> >> > +		return PTR_ERR(base);
>> >> > +
>> >> > +	fsl_dev->tcon_regmap = devm_regmap_init_mmio_clk(&pdev->dev,
>> >> > +			"tcon", base, &fsl_dcu_regmap_config);
>> >>
>> >> And implicitly using regmap. In a short test on Vybrid, the clock is
>> >> actually not needed during operation, hence we could use the explicit
>> >> enabling above, what do you think?
>> >>
>> >> Also, the clock and tcon in general currently does not get handled by
>> >> suspend/resume code...
>> >>
>> >
>> > OK, I'll update code here
>> >
>> >> > +	if (IS_ERR(fsl_dev->tcon_regmap)) {
>> >> > +		dev_err(&pdev->dev, "regmap init failed\n");
>> >> > +		return PTR_ERR(fsl_dev->tcon_regmap);
>> >> > +	}
>> >> > +
>> >> > +	regmap_write(fsl_dev->tcon_regmap, TCON_CTRL1,
>> TCON_BYPASS_ENABLE);
>> >> > +	return 0;
>> >> > +}
>> >> > +
>> >> > +static int fsl_dcu_drm_irq_init(struct drm_device *dev)
>> >> > +{
>> >> > +	struct platform_device *pdev = dev->platformdev;
>> >> > +	struct fsl_dcu_drm_device *fsl_dev = dev->dev_private;
>> >> > +	unsigned int int_mask;
>> >> > +	int ret;
>> >> > +
>> >> > +	ret = drm_irq_install(dev, platform_get_irq(dev->platformdev,
>> 0));
>> >> > +	if (ret < 0)
>> >> > +		dev_err(&pdev->dev, "failed to install IRQ handler\n");
>> >> > +
>> >> > +	dev->irq_enabled = true;
>> >> > +	dev->vblank_disable_allowed = true;
>> >> > +
>> >> > +	regmap_write(fsl_dev->regmap, DCU_INT_STATUS, 0);
>> >> > +	regmap_read(fsl_dev->regmap, DCU_INT_MASK, &int_mask);
>> >> > +	regmap_write(fsl_dev->regmap, DCU_INT_MASK, int_mask &
>> >> > +		     ~DCU_INT_MASK_VBLANK);
>> >> > +	regmap_write(fsl_dev->regmap, DCU_UPDATE_MODE,
>> >> DCU_UPDATE_MODE_READREG);
>> >> > +
>> >> > +	return 0;
>> >> > +}
>> >> > +
>> >> > +static int fsl_dcu_load(struct drm_device *dev, unsigned long flags)
>> >> > +{
>> >> > +	struct platform_device *pdev = dev->platformdev;
>> >> > +	struct fsl_dcu_drm_device *fsl_dev;
>> >> > +	struct resource *res;
>> >> > +	void __iomem *base;
>> >> > +	int ret;
>> >> > +
>> >> > +	fsl_dev = devm_kzalloc(&pdev->dev, sizeof(*fsl_dev),
>> GFP_KERNEL);
>> >> > +	if (!fsl_dev)
>> >> > +		return -ENOMEM;
>> >> > +
>> >> > +	fsl_dev->dev = &pdev->dev;
>> >> > +	fsl_dev->ddev = dev;
>> >> > +	fsl_dev->np = pdev->dev.of_node;
>> >> > +	dev->dev_private = fsl_dev;
>> >> > +	drm_dev_set_unique(dev, dev_name(dev->dev));
>> >> > +
>> >> > +	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
>> >> > +	if (!res) {
>> >> > +		dev_err(&pdev->dev, "could not get memory IO
>> resource\n");
>> >> > +		return -ENODEV;
>> >> > +	}
>> >> > +
>> >> > +	base = devm_ioremap_resource(&pdev->dev, res);
>> >> > +	if (IS_ERR(base)) {
>> >> > +		ret = PTR_ERR(base);
>> >> > +		return ret;
>> >> > +	}
>> >> > +
>> >> > +	fsl_dev->regmap = devm_regmap_init_mmio_clk(&pdev->dev, NULL,
>> >> > +			base, &fsl_dcu_regmap_config);
>> >> > +	if (IS_ERR(fsl_dev->regmap)) {
>> >> > +		dev_err(&pdev->dev, "regmap init failed\n");
>> >> > +		return PTR_ERR(fsl_dev->regmap);
>> >> > +	}
>> >> > +
>> >> > +	/* Put TCON in bypass mode, so the input signals from DCU are
>> passed
>> >> > +	 * through TCON unchanged */
>> >> > +	fsl_dcu_bypass_tcon(fsl_dev, fsl_dev->np);
>> >> > +	fsl_dev->clk = devm_clk_get(&pdev->dev, "dcu");
>> >> > +	if (IS_ERR(fsl_dev->clk)) {
>> >> > +		ret = PTR_ERR(fsl_dev->clk);
>> >> > +		dev_err(&pdev->dev, "could not get clock\n");
>> >> > +		return ret;
>> >> > +	}
>> >> > +	clk_prepare_enable(fsl_dev->clk);
>> >> > +	dev_set_drvdata(dev->dev, fsl_dev);
>> >> > +
>> >> > +	ret = fsl_dcu_drm_modeset_init(fsl_dev);
>> >> > +	if (ret < 0) {
>> >> > +		dev_err(&pdev->dev, "failed to initialize mode
>> setting\n");
>> >> > +		return ret;
>> >> > +	}
>> >> > +
>> >> > +	ret = drm_vblank_init(dev, dev->mode_config.num_crtc);
>> >> > +	if (ret < 0) {
>> >> > +		dev_err(&pdev->dev, "failed to initialize vblank\n");
>> >> > +		goto done;
>> >> > +	}
>> >> > +
>> >> > +	ret = fsl_dcu_drm_irq_init(dev);
>> >> > +	if (ret < 0)
>> >> > +		goto done;
>> >> > +
>> >> > +	fsl_dcu_fbdev_init(dev);
>> >> > +
>> >> > +	return 0;
>> >> > +done:
>> >> > +	if (ret)
>> >> > +		fsl_dcu_unload(dev);
>> >> > +
>> >> > +	return ret;
>> >> > +}
>> >> > +
>> >> > +static void fsl_dcu_drm_preclose(struct drm_device *dev, struct
>> >> drm_file *file)
>> >> > +{
>> >> > +	;
>> >> > +}
>> >> > +
>> >> > +static irqreturn_t fsl_dcu_drm_irq(int irq, void *arg)
>> >> > +{
>> >> > +	struct drm_device *dev = arg;
>> >> > +	struct fsl_dcu_drm_device *fsl_dev = dev->dev_private;
>> >> > +	unsigned int int_status;
>> >> > +
>> >> > +	regmap_read(fsl_dev->regmap, DCU_INT_STATUS, &int_status);
>> >> > +	if (int_status & DCU_INT_STATUS_VBLANK)
>> >> > +		drm_handle_vblank(dev, 0);
>> >> > +
>> >> > +	regmap_write(fsl_dev->regmap, DCU_INT_STATUS, 0xffffffff);
>> >> > +	regmap_write(fsl_dev->regmap, DCU_UPDATE_MODE,
>> >> DCU_UPDATE_MODE_READREG);
>> >> > +
>> >> > +	return IRQ_HANDLED;
>> >> > +}
>> >> > +
>> >> > +static int fsl_dcu_drm_enable_vblank(struct drm_device *dev, int
>> crtc)
>> >> > +{
>> >> > +	return 0;
>> >> > +}
>> >> > +
>> >> > +static void fsl_dcu_drm_disable_vblank(struct drm_device *dev, int
>> crtc)
>> >> > +{
>> >> > +	;
>> >> > +}
>> >> > +
>> >> > +static const struct file_operations fsl_dcu_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		= no_llseek,
>> >> > +	.mmap		= drm_gem_cma_mmap,
>> >> > +};
>> >> > +
>> >> > +static struct drm_driver fsl_dcu_drm_driver = {
>> >> > +	.driver_features	= DRIVER_HAVE_IRQ | DRIVER_GEM |
>> DRIVER_MODESET
>> >> > +				| DRIVER_PRIME,
>> >> > +	.load			= fsl_dcu_load,
>> >> > +	.unload			= fsl_dcu_unload,
>> >> > +	.preclose		= fsl_dcu_drm_preclose,
>> >> > +	.irq_handler		= fsl_dcu_drm_irq,
>> >> > +	.get_vblank_counter	= drm_vblank_count,
>> >> > +	.enable_vblank		= fsl_dcu_drm_enable_vblank,
>> >> > +	.disable_vblank		= fsl_dcu_drm_disable_vblank,
>> >> > +	.gem_free_object	= drm_gem_cma_free_object,
>> >> > +	.gem_vm_ops		= &drm_gem_cma_vm_ops,
>> >> > +	.prime_handle_to_fd	= drm_gem_prime_handle_to_fd,
>> >> > +	.prime_fd_to_handle	= drm_gem_prime_fd_to_handle,
>> >> > +	.gem_prime_import	= drm_gem_prime_import,
>> >> > +	.gem_prime_export	= drm_gem_prime_export,
>> >> > +	.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,
>> >> > +	.dumb_create		= drm_gem_cma_dumb_create,
>> >> > +	.dumb_map_offset	= drm_gem_cma_dumb_map_offset,
>> >> > +	.dumb_destroy		= drm_gem_dumb_destroy,
>> >> > +	.fops			= &fsl_dcu_drm_fops,
>> >> > +	.name			= "fsl-dcu-drm",
>> >> > +	.desc			= "Freescale DCU DRM",
>> >> > +	.date			= "20150213",
>> >> > +	.major			= 1,
>> >> > +	.minor			= 0,
>> >> > +};
>> >> > +
>> >> > +#ifdef CONFIG_PM_SLEEP
>> >> > +static int fsl_dcu_drm_pm_suspend(struct device *dev)
>> >> > +{
>> >> > +	struct fsl_dcu_drm_device *fsl_dev = dev_get_drvdata(dev);
>> >> > +
>> >> > +	if (of_device_is_compatible(fsl_dev->np, "fsl,ls1021a-dcu"))
>> >> > +		dcu_pixclk_disable();
>> >> > +
>> >> > +	drm_kms_helper_poll_disable(fsl_dev->ddev);
>> >> > +	fsl_dcu_drm_crtc_suspend(&fsl_dev->crtc);
>> >>
>> >> I get
>> >>
>> >> drivers/gpu/drm/fsl/fsl_dcu_drm_drv.c: In function
>> >> 'fsl_dcu_drm_pm_suspend':
>> >> drivers/gpu/drm/fsl/fsl_dcu_drm_drv.c:270:2: error: implicit
>> declaration
>> >> of function 'fsl_dcu_drm_crtc_suspend'
>> >> [-Werror=implicit-function-declaration]
>> >>   fsl_dcu_drm_crtc_suspend(&fsl_dev->crtc);
>> >>   ^
>> >> drivers/gpu/drm/fsl/fsl_dcu_drm_drv.c: In function
>> >> 'fsl_dcu_drm_pm_resume':
>> >> drivers/gpu/drm/fsl/fsl_dcu_drm_drv.c:280:2: error: implicit
>> declaration
>> >> of function 'fsl_dcu_drm_crtc_resume'
>> >> [-Werror=implicit-function-declaration]
>> >>   fsl_dcu_drm_crtc_resume(&fsl_dev->crtc);
>> >>   ^
>> >>
>> >> The function fsl_dcu_drm_crtc_suspend seems to be part of
>> >> fsl_dcu_drm_crtc.c, but is empty. While the other is missing
>> >> completely... Please fix/remove as appropriate.
>> >>
>> >
>> > OK, I'll fix it
>> >
>> > Regards
>> > Jianwei
>> >> > +
>> >> > +	return 0;
>> >> > +}
>> >> > +
>> >> > +static int fsl_dcu_drm_pm_resume(struct device *dev)
>> >> > +{
>> >> > +	struct fsl_dcu_drm_device *fsl_dev = dev_get_drvdata(dev);
>> >> > +
>> >> > +	drm_modeset_lock_all(fsl_dev->ddev);
>> >> > +	fsl_dcu_drm_crtc_resume(&fsl_dev->crtc);
>> >> > +	drm_modeset_unlock_all(fsl_dev->ddev);
>> >> > +	drm_kms_helper_poll_enable(fsl_dev->ddev);
>> >> > +
>> >> > +	if (of_device_is_compatible(fsl_dev->np, "fsl,ls1021a-dcu"))
>> >> > +		dcu_pixclk_enable();
>> >> > +
>> >> > +	return 0;
>> >> > +}
>> >> > +#endif
>> >> > +
>> >> > +static const struct dev_pm_ops fsl_dcu_drm_pm_ops = {
>> >> > +	SET_SYSTEM_SLEEP_PM_OPS(fsl_dcu_drm_pm_suspend,
>> >> fsl_dcu_drm_pm_resume)
>> >> > +};
>> >> > +
>> >> > +static int fsl_dcu_drm_probe(struct platform_device *pdev)
>> >> > +{
>> >> > +	return drm_platform_init(&fsl_dcu_drm_driver, pdev);
>> >> > +}
>> >> > +
>> >> > +static int fsl_dcu_drm_remove(struct platform_device *pdev)
>> >> > +{
>> >> > +	struct fsl_dcu_drm_device *fsl_dev =
>> platform_get_drvdata(pdev);
>> >> > +
>> >> > +	drm_put_dev(fsl_dev->ddev);
>> >> > +
>> >> > +	return 0;
>> >> > +}
>> >> > +
>> >> > +static const struct of_device_id fsl_dcu_of_match[] = {
>> >> > +		{ .compatible = "fsl,ls1021a-dcu", },
>> >> > +		{ .compatible = "fsl,vf610-dcu", },
>> >> > +		{ },
>> >> > +};
>> >> > +MODULE_DEVICE_TABLE(of, fsl_dcu_of_match);
>> >> > +
>> >> > +static struct platform_driver fsl_dcu_drm_platform_driver = {
>> >> > +	.probe		= fsl_dcu_drm_probe,
>> >> > +	.remove		= fsl_dcu_drm_remove,
>> >> > +	.driver		= {
>> >> > +		.owner	= THIS_MODULE,
>> >> > +		.name	= "fsl,dcu",
>> >> > +		.pm	= &fsl_dcu_drm_pm_ops,
>> >> > +		.of_match_table = fsl_dcu_of_match,
>> >> > +	},
>> >> > +};
>> >> > +
>> >> > +module_platform_driver(fsl_dcu_drm_platform_driver);
>> >> > +
>> >> > +MODULE_ALIAS("platform:fsl-dcu-drm");
>> >> > +MODULE_DESCRIPTION("Freescale DCU DRM Driver");
>> >> > +MODULE_LICENSE("GPL");
>> >> > diff --git a/drivers/gpu/drm/fsl/fsl_dcu_drm_drv.h
>> >> > b/drivers/gpu/drm/fsl/fsl_dcu_drm_drv.h
>> >> > new file mode 100644
>> >> > index 0000000..27226109
>> >> > --- /dev/null
>> >> > +++ b/drivers/gpu/drm/fsl/fsl_dcu_drm_drv.h
>> >> > @@ -0,0 +1,210 @@
>> >> > +/*
>> >> > + * Copyright 2015 Freescale Semiconductor, Inc.
>> >> > + *
>> >> > + * Freescale DCU drm device driver
>> >> > + *
>> >> > + * 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 __FSL_DCU_DRM_DRV_H__
>> >> > +#define __FSL_DCU_DRM_DRV_H__
>> >> > +
>> >> > +#include <linux/kernel.h>
>> >> > +#include <linux/spinlock.h>
>> >> > +#include <stddef.h>
>> >> > +#include <drm/drm.h>
>> >> > +#include <drm/drmP.h>
>> >> > +#include <drm/drm_fb_helper.h>
>> >> > +#include <drm/drm_crtc_helper.h>
>> >> > +#include <drm/drm_gem_cma_helper.h>
>> >> > +#include <drm/drm_fb_cma_helper.h>
>> >> > +
>> >> > +#include "fsl_dcu_drm_crtc.h"
>> >> > +#include "fsl_dcu_drm_plane.h"
>> >> > +#include "fsl_dcu_drm_connector.h"
>> >> > +#define DRIVER_NAME			"fsl-dcu-drm"
>> >> > +
>> >> > +#define DCU_DCU_MODE			0x0010
>> >> > +#define DCU_MODE_BLEND_ITER(x)		((x) << 20)
>> >> > +#define DCU_MODE_RASTER_EN		BIT(14)
>> >> > +#define DCU_MODE_DCU_MODE(x)		(x)
>> >> > +#define DCU_MODE_DCU_MODE_MASK		0x03
>> >> > +#define DCU_MODE_OFF			0
>> >> > +#define DCU_MODE_NORMAL			1
>> >> > +#define DCU_MODE_TEST			2
>> >> > +#define DCU_MODE_COLORBAR		3
>> >> > +
>> >> > +#define DCU_BGND			0x0014
>> >> > +#define DCU_BGND_R(x)			((x) << 16)
>> >> > +#define DCU_BGND_G(x)			((x) << 8)
>> >> > +#define DCU_BGND_B(x)			(x)
>> >> > +
>> >> > +#define DCU_DISP_SIZE			0x0018
>> >> > +#define DCU_DISP_SIZE_DELTA_Y(x)	((x) << 16)
>> >> > +/*Regisiter value 1/16 of horizontal resolution*/
>> >> > +#define DCU_DISP_SIZE_DELTA_X(x)	((x) >> 4)
>> >> > +
>> >> > +#define DCU_HSYN_PARA			0x001c
>> >> > +#define DCU_HSYN_PARA_BP(x)		((x) << 22)
>> >> > +#define DCU_HSYN_PARA_PW(x)		((x) << 11)
>> >> > +#define DCU_HSYN_PARA_FP(x)		(x)
>> >> > +
>> >> > +#define DCU_VSYN_PARA			0x0020
>> >> > +#define DCU_VSYN_PARA_BP(x)		((x) << 22)
>> >> > +#define DCU_VSYN_PARA_PW(x)		((x) << 11)
>> >> > +#define DCU_VSYN_PARA_FP(x)		(x)
>> >> > +
>> >> > +#define DCU_SYN_POL			0x0024
>> >> > +#define DCU_SYN_POL_INV_PXCK_FALL	(0 << 6)
>> >> > +#define DCU_SYN_POL_NEG_REMAIN		(0 << 5)
>> >> > +#define DCU_SYN_POL_INV_VS_LOW		BIT(1)
>> >> > +#define DCU_SYN_POL_INV_HS_LOW		BIT(0)
>> >> > +
>> >> > +#define DCU_THRESHOLD			0x0028
>> >> > +#define DCU_THRESHOLD_LS_BF_VS(x)	((x) << 16)
>> >> > +#define DCU_THRESHOLD_OUT_BUF_HIGH(x)	((x) << 8)
>> >> > +#define DCU_THRESHOLD_OUT_BUF_LOW(x)	(x)
>> >> > +#define BF_VS_VAL			0x03
>> >> > +#define BUF_MAX_VAL			0x78
>> >> > +#define BUF_MIN_VAL			0x0a
>> >> > +
>> >> > +#define DCU_INT_STATUS			0x002C
>> >> > +#define DCU_INT_STATUS_VSYNC		BIT(0)
>> >> > +#define DCU_INT_STATUS_UNDRUN		BIT(1)
>> >> > +#define DCU_INT_STATUS_LSBFVS		BIT(2)
>> >> > +#define DCU_INT_STATUS_VBLANK		BIT(3)
>> >> > +#define DCU_INT_STATUS_CRCREADY		BIT(4)
>> >> > +#define DCU_INT_STATUS_CRCOVERFLOW	BIT(5)
>> >> > +#define DCU_INT_STATUS_P1FIFOLO		BIT(6)
>> >> > +#define DCU_INT_STATUS_P1FIFOHI		BIT(7)
>> >> > +#define DCU_INT_STATUS_P2FIFOLO		BIT(8)
>> >> > +#define DCU_INT_STATUS_P2FIFOHI		BIT(9)
>> >> > +#define DCU_INT_STATUS_PROGEND		BIT(10)
>> >> > +#define DCU_INT_STATUS_IPMERROR		BIT(11)
>> >> > +#define DCU_INT_STATUS_LYRTRANS		BIT(12)
>> >> > +#define DCU_INT_STATUS_DMATRANS		BIT(14)
>> >> > +#define DCU_INT_STATUS_P3FIFOLO		BIT(16)
>> >> > +#define DCU_INT_STATUS_P3FIFOHI		BIT(17)
>> >> > +#define DCU_INT_STATUS_P4FIFOLO		BIT(18)
>> >> > +#define DCU_INT_STATUS_P4FIFOHI		BIT(19)
>> >> > +#define DCU_INT_STATUS_P1EMPTY		BIT(26)
>> >> > +#define DCU_INT_STATUS_P2EMPTY		BIT(27)
>> >> > +#define DCU_INT_STATUS_P3EMPTY		BIT(28)
>> >> > +#define DCU_INT_STATUS_P4EMPTY		BIT(29)
>> >> > +
>> >> > +#define DCU_INT_MASK			0x0030
>> >> > +#define DCU_INT_MASK_VSYNC		BIT(0)
>> >> > +#define DCU_INT_MASK_UNDRUN		BIT(1)
>> >> > +#define DCU_INT_MASK_LSBFVS		BIT(2)
>> >> > +#define DCU_INT_MASK_VBLANK		BIT(3)
>> >> > +#define DCU_INT_MASK_CRCREADY		BIT(4)
>> >> > +#define DCU_INT_MASK_CRCOVERFLOW	BIT(5)
>> >> > +#define DCU_INT_MASK_P1FIFOLO		BIT(6)
>> >> > +#define DCU_INT_MASK_P1FIFOHI		BIT(7)
>> >> > +#define DCU_INT_MASK_P2FIFOLO		BIT(8)
>> >> > +#define DCU_INT_MASK_P2FIFOHI		BIT(9)
>> >> > +#define DCU_INT_MASK_PROGEND		BIT(10)
>> >> > +#define DCU_INT_MASK_IPMERROR		BIT(11)
>> >> > +#define DCU_INT_MASK_LYRTRANS		BIT(12)
>> >> > +#define DCU_INT_MASK_DMATRANS		BIT(14)
>> >> > +#define DCU_INT_MASK_P3FIFOLO		BIT(16)
>> >> > +#define DCU_INT_MASK_P3FIFOHI		BIT(17)
>> >> > +#define DCU_INT_MASK_P4FIFOLO		BIT(18)
>> >> > +#define DCU_INT_MASK_P4FIFOHI		BIT(19)
>> >> > +#define DCU_INT_MASK_P1EMPTY		BIT(26)
>> >> > +#define DCU_INT_MASK_P2EMPTY		BIT(27)
>> >> > +#define DCU_INT_MASK_P3EMPTY		BIT(28)
>> >> > +#define DCU_INT_MASK_P4EMPTY		BIT(29)
>> >> > +
>> >> > +#define DCU_DIV_RATIO			0x0054
>> >> > +
>> >> > +#define DCU_UPDATE_MODE			0x00cc
>> >> > +#define DCU_UPDATE_MODE_MODE		BIT(31)
>> >> > +#define DCU_UPDATE_MODE_READREG		BIT(30)
>> >> > +
>> >> > +#define DCU_DCFB_MAX			0x300
>> >> > +
>> >> > +#define DCU_CTRLDESCLN_1(x)		(0x200 + (x) * 0x40)
>> >> > +#define DCU_CTRLDESCLN_1_HEIGHT(x)	((x) << 16)
>> >> > +#define DCU_CTRLDESCLN_1_WIDTH(x)	(x)
>> >> > +
>> >> > +#define DCU_CTRLDESCLN_2(x)		(0x204 + (x) * 0x40)
>> >> > +#define DCU_CTRLDESCLN_2_POSY(x)	((x) << 16)
>> >> > +#define DCU_CTRLDESCLN_2_POSX(x)	(x)
>> >> > +
>> >> > +#define DCU_CTRLDESCLN_3(x)		(0x208 + (x) * 0x40)
>> >> > +
>> >> > +#define DCU_CTRLDESCLN_4(x)		(0x20c + (x) * 0x40)
>> >> > +#define DCU_CTRLDESCLN_4_EN		BIT(31)
>> >> > +#define DCU_CTRLDESCLN_4_TILE_EN	BIT(30)
>> >> > +#define DCU_CTRLDESCLN_4_DATA_SEL_CLUT	BIT(29)
>> >> > +#define DCU_CTRLDESCLN_4_SAFETY_EN	BIT(28)
>> >> > +#define DCU_CTRLDESCLN_4_TRANS(x)	((x) << 20)
>> >> > +#define DCU_CTRLDESCLN_4_BPP(x)		((x) << 16)
>> >> > +#define DCU_CTRLDESCLN_4_RLE_EN		BIT(15)
>> >> > +#define DCU_CTRLDESCLN_4_LUOFFS(x)	((x) << 4)
>> >> > +#define DCU_CTRLDESCLN_4_BB_ON		BIT(2)
>> >> > +#define DCU_CTRLDESCLN_4_AB(x)		(x)
>> >> > +
>> >> > +#define DCU_CTRLDESCLN_5(x)		(0x210 + (x) * 0x40)
>> >> > +#define DCU_CTRLDESCLN_5_CKMAX_R(x)	((x) << 16)
>> >> > +#define DCU_CTRLDESCLN_5_CKMAX_G(x)	((x) << 8)
>> >> > +#define DCU_CTRLDESCLN_5_CKMAX_B(x)	(x)
>> >> > +
>> >> > +#define DCU_CTRLDESCLN_6(x)		(0x214 + (x) * 0x40)
>> >> > +#define DCU_CTRLDESCLN_6_CKMIN_R(x)	((x) << 16)
>> >> > +#define DCU_CTRLDESCLN_6_CKMIN_G(x)	((x) << 8)
>> >> > +#define DCU_CTRLDESCLN_6_CKMIN_B(x)	(x)
>> >> > +
>> >> > +#define DCU_CTRLDESCLN_7(x)		(0x218 + (x) * 0x40)
>> >> > +#define DCU_CTRLDESCLN_7_TILE_VER(x)	((x) << 16)
>> >> > +#define DCU_CTRLDESCLN_7_TILE_HOR(x)	(x)
>> >> > +
>> >> > +#define DCU_CTRLDESCLN_8(x)		(0x21c + (x) * 0x40)
>> >> > +#define DCU_CTRLDESCLN_8_FG_FCOLOR(x)	(x)
>> >> > +
>> >> > +#define DCU_CTRLDESCLN_9(x)		(0x220 + (x) * 0x40)
>> >> > +#define DCU_CTRLDESCLN_9_BG_BCOLOR(x)	(x)
>> >> > +
>> >> > +#define DCU_CTRLDESCLN_10(x)		(0x224 + (x) * 0x40)
>> >> > +#define DCU_CTRLDESCLN_10_POST_SKIP(x)	((x) << 16)
>> >> > +#define DCU_CTRLDESCLN_10_PRE_SKIP(x)	(x)
>> >> > +
>> >> > +#define FSL_DCU_RGB565			4
>> >> > +#define FSL_DCU_RGB888			5
>> >> > +#define FSL_DCU_ARGB8888		6
>> >> > +#define FSL_DCU_ARGB1555		11
>> >> > +#define FSL_DCU_ARGB4444		12
>> >> > +#define FSL_DCU_YUV422			14
>> >> > +
>> >> > +#define TCON_CTRL1			0x0000
>> >> > +#define TCON_BYPASS_ENABLE		BIT(29)
>> >> > +
>> >> > +#define DBG(fmt, ...) DRM_DEBUG(fmt"\n", ##__VA_ARGS__)
>> >> > +
>> >> > +struct clk;
>> >> > +struct device;
>> >> > +struct drm_device;
>> >> > +
>> >> > +struct fsl_dcu_drm_device {
>> >> > +	struct device *dev;
>> >> > +	struct device_node *np;
>> >> > +	struct regmap *regmap;
>> >> > +	struct regmap *tcon_regmap;
>> >> > +	unsigned int irq;
>> >> > +	struct clk *clk;
>> >> > +	/*protects hardware register*/
>> >> > +	spinlock_t irq_lock;
>> >> > +	struct drm_device *ddev;
>> >> > +	struct drm_fbdev_cma *fbdev;
>> >> > +	struct fsl_dcu_drm_crtc crtc;
>> >> > +	struct drm_encoder encoder;
>> >> > +	struct fsl_dcu_drm_connector connector;
>> >> > +};
>> >> > +
>> >> > +void fsl_dcu_fbdev_init(struct drm_device *dev);
>> >> > +
>> >> > +#endif /* __FSL_DCU_DRM_DRV_H__ */
>> >> > diff --git a/drivers/gpu/drm/fsl/fsl_dcu_drm_fbdev.c
>> >> > b/drivers/gpu/drm/fsl/fsl_dcu_drm_fbdev.c
>> >> > new file mode 100644
>> >> > index 0000000..f8ef0e1
>> >> > --- /dev/null
>> >> > +++ b/drivers/gpu/drm/fsl/fsl_dcu_drm_fbdev.c
>> >> > @@ -0,0 +1,26 @@
>> >> > +/*
>> >> > + * Copyright 2015 Freescale Semiconductor, Inc.
>> >> > + *
>> >> > + * 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.
>> >> > + *
>> >> > + * This program is distributed in the hope that it will be useful,
>> but
>> >> WITHOUT
>> >> > + * ANY WARRANTY; without even the implied warranty of
>> MERCHANTABILITY
>> >> or
>> >> > + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
>> >> License for
>> >> > + * more details.
>> >> > + *
>> >> > + */
>> >> > +
>> >> > +#include <drm/drmP.h>
>> >> > +#include <drm/drm_fb_cma_helper.h>
>> >> > +
>> >> > +#include "fsl_dcu_drm_drv.h"
>> >> > +
>> >> > +/* initialize fbdev helper */
>> >> > +void fsl_dcu_fbdev_init(struct drm_device *dev)
>> >> > +{
>> >> > +	struct fsl_dcu_drm_device *fsl_dev = dev_get_drvdata(dev->dev);
>> >> > +
>> >> > +	fsl_dev->fbdev = drm_fbdev_cma_init(dev, 24, 1, 1);
>> >> > +}
>> >> > diff --git a/drivers/gpu/drm/fsl/fsl_dcu_drm_kms.c
>> >> > b/drivers/gpu/drm/fsl/fsl_dcu_drm_kms.c
>> >> > new file mode 100644
>> >> > index 0000000..0de21c6
>> >> > --- /dev/null
>> >> > +++ b/drivers/gpu/drm/fsl/fsl_dcu_drm_kms.c
>> >> > @@ -0,0 +1,42 @@
>> >> > +/*
>> >> > + * Copyright 2015 Freescale Semiconductor, Inc.
>> >> > + *
>> >> > + * Freescale DCU drm device driver
>> >> > + *
>> >> > + * 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 "fsl_dcu_drm_crtc.h"
>> >> > +#include "fsl_dcu_drm_connector.h"
>> >> > +#include "fsl_dcu_drm_drv.h"
>> >> > +
>> >> > +static const struct drm_mode_config_funcs
>> fsl_dcu_drm_mode_config_funcs
>> >> = {
>> >> > +	.fb_create = drm_fb_cma_create,
>> >> > +	.atomic_check = drm_atomic_helper_check,
>> >> > +	.atomic_commit = drm_atomic_helper_commit,
>> >> > +};
>> >> > +
>> >> > +int fsl_dcu_drm_modeset_init(struct fsl_dcu_drm_device *fsl_dev)
>> >> > +{
>> >> > +	drm_mode_config_init(fsl_dev->ddev);
>> >> > +
>> >> > +	fsl_dev->ddev->mode_config.min_width = 0;
>> >> > +	fsl_dev->ddev->mode_config.min_height = 0;
>> >> > +	fsl_dev->ddev->mode_config.max_width = 2031;
>> >> > +	fsl_dev->ddev->mode_config.max_height = 2047;
>> >> > +	fsl_dev->ddev->mode_config.funcs =
>> &fsl_dcu_drm_mode_config_funcs;
>> >> > +
>> >> > +	drm_kms_helper_poll_init(fsl_dev->ddev);
>> >> > +	fsl_dcu_drm_crtc_create(fsl_dev);
>> >> > +	fsl_dcu_drm_encoder_create(fsl_dev, &fsl_dev->crtc);
>> >> > +	fsl_dcu_drm_connector_create(fsl_dev, &fsl_dev->encoder);
>> >> > +	drm_mode_config_reset(fsl_dev->ddev);
>> >> > +
>> >> > +	return 0;
>> >> > +}
>> >> > diff --git a/drivers/gpu/drm/fsl/fsl_dcu_drm_kms.h
>> >> > b/drivers/gpu/drm/fsl/fsl_dcu_drm_kms.h
>> >> > new file mode 100644
>> >> > index 0000000..b9bd299
>> >> > --- /dev/null
>> >> > +++ b/drivers/gpu/drm/fsl/fsl_dcu_drm_kms.h
>> >> > @@ -0,0 +1,17 @@
>> >> > +/*
>> >> > + * Copyright 2015 Freescale Semiconductor, Inc.
>> >> > + *
>> >> > + * Freescale DCU drm device driver
>> >> > + *
>> >> > + * 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 __FSL_DCU_DRM_KMS_H__
>> >> > +#define __FSL_DCU_DRM_KMS_H__
>> >> > +
>> >> > +int fsl_dcu_drm_modeset_init(struct fsl_dcu_drm_device *fsl_dev);
>> >> > +
>> >> > +#endif /* __FSL_DCU_DRM_KMS_H__ */
>> >> > diff --git a/drivers/gpu/drm/fsl/fsl_dcu_drm_plane.c
>> >> > b/drivers/gpu/drm/fsl/fsl_dcu_drm_plane.c
>> >> > new file mode 100644
>> >> > index 0000000..6146e80
>> >> > --- /dev/null
>> >> > +++ b/drivers/gpu/drm/fsl/fsl_dcu_drm_plane.c
>> >> > @@ -0,0 +1,192 @@
>> >> > +/*
>> >> > + * Copyright 2015 Freescale Semiconductor, Inc.
>> >> > + *
>> >> > + * Freescale DCU drm device driver
>> >> > + *
>> >> > + * 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_crtc.h>
>> >> > +#include <drm/drm_crtc_helper.h>
>> >> > +#include <drm/drm_fb_cma_helper.h>
>> >> > +#include <drm/drm_gem_cma_helper.h>
>> >> > +#include <linux/regmap.h>
>> >> > +#include <drm/drm_plane_helper.h>
>> >> > +#include <drm/drm_atomic_helper.h>
>> >> > +
>> >> > +#include "fsl_dcu_drm_drv.h"
>> >> > +#include "fsl_dcu_drm_kms.h"
>> >> > +#include "fsl_dcu_drm_plane.h"
>> >> > +
>> >> > +#define to_fsl_dcu_plane(plane) \
>> >> > +	container_of(plane, struct fsl_dcu_drm_plane, plane)
>> >> > +
>> >> > +static int
>> >> > +fsl_dcu_drm_plane_prepare_fb(struct drm_plane *plane,
>> >> > +			     struct drm_framebuffer *fb,
>> >> > +			     const struct drm_plane_state *new_state)
>> >> > +{
>> >> > +	return 0;
>> >> > +}
>> >> > +
>> >> > +static void
>> >> > +fsl_dcu_drm_plane_cleanup_fb(struct drm_plane *plane,
>> >> > +			     struct drm_framebuffer *fb,
>> >> > +			     const struct drm_plane_state *new_state)
>> >> > +{
>> >> > +}
>> >> > +
>> >> > +static int fsl_dcu_drm_plane_atomic_check(struct drm_plane *plane,
>> >> > +					  struct drm_plane_state *state)
>> >> > +{
>> >> > +	return 0;
>> >> > +}
>> >> > +
>> >> > +static void fsl_dcu_drm_plane_atomic_disable(struct drm_plane *plane,
>> >> > +					     struct drm_plane_state *old_state)
>> >> > +{
>> >> > +}
>> >> > +
>> >> > +void fsl_dcu_drm_plane_atomic_update(struct drm_plane *plane,
>> >> > +				     struct drm_plane_state *old_state)
>> >> > +{
>> >> > +	struct fsl_dcu_drm_device *fsl_dev = plane->dev->dev_private;
>> >> > +	struct drm_plane_state *state = plane->state;
>> >> > +	struct drm_framebuffer *fb = plane->state->fb;
>> >> > +	u32 index, alpha, bpp;
>> >> > +	struct drm_gem_cma_object *gem;
>> >> > +	struct fsl_dcu_drm_plane *fsl_plane = to_fsl_dcu_plane(plane);
>> >> > +
>> >> > +	index = fsl_plane->index;
>> >> > +	gem = drm_fb_cma_get_gem_obj(fb, 0);
>> >> > +
>> >> > +	switch (fb->pixel_format) {
>> >> > +	case DRM_FORMAT_RGB565:
>> >> > +		bpp = FSL_DCU_RGB565;
>> >> > +		alpha = 0xff;
>> >> > +		break;
>> >> > +	case DRM_FORMAT_RGB888:
>> >> > +		bpp = FSL_DCU_RGB888;
>> >> > +		alpha = 0xff;
>> >> > +		break;
>> >> > +	case DRM_FORMAT_ARGB8888:
>> >> > +		bpp = FSL_DCU_ARGB8888;
>> >> > +		alpha = 0xff;
>> >> > +		break;
>> >> > +	case DRM_FORMAT_BGRA4444:
>> >> > +		bpp = FSL_DCU_ARGB4444;
>> >> > +		alpha = 0xff;
>> >> > +		break;
>> >> > +	case DRM_FORMAT_ARGB1555:
>> >> > +		bpp = FSL_DCU_ARGB1555;
>> >> > +		alpha = 0xff;
>> >> > +		break;
>> >> > +	case DRM_FORMAT_YUV422:
>> >> > +		bpp = FSL_DCU_YUV422;
>> >> > +		alpha = 0xff;
>> >> > +		break;
>> >> > +	default:
>> >> > +		return;
>> >> > +	}
>> >> > +
>> >> > +	regmap_write(fsl_dev->regmap, DCU_CTRLDESCLN_1(index),
>> >> > +		     DCU_CTRLDESCLN_1_HEIGHT(state->crtc_h) |
>> >> > +		     DCU_CTRLDESCLN_1_WIDTH(state->crtc_w));
>> >> > +	regmap_write(fsl_dev->regmap, DCU_CTRLDESCLN_2(index),
>> >> > +		     DCU_CTRLDESCLN_2_POSY(state->crtc_y) |
>> >> > +		     DCU_CTRLDESCLN_2_POSX(state->crtc_x));
>> >> > +	regmap_write(fsl_dev->regmap, DCU_CTRLDESCLN_3(index), gem-
>> >paddr);
>> >> > +	regmap_write(fsl_dev->regmap, DCU_CTRLDESCLN_4(index),
>> >> > +		     DCU_CTRLDESCLN_4_EN |
>> >> > +		     DCU_CTRLDESCLN_4_TRANS(alpha) |
>> >> > +		     DCU_CTRLDESCLN_4_BPP(bpp) |
>> >> > +		     DCU_CTRLDESCLN_4_AB(0));
>> >> > +	regmap_write(fsl_dev->regmap, DCU_CTRLDESCLN_5(index),
>> >> > +		     DCU_CTRLDESCLN_5_CKMAX_R(0xFF) |
>> >> > +		     DCU_CTRLDESCLN_5_CKMAX_G(0xFF) |
>> >> > +		     DCU_CTRLDESCLN_5_CKMAX_B(0xFF));
>> >> > +	regmap_write(fsl_dev->regmap, DCU_CTRLDESCLN_6(index),
>> >> > +		     DCU_CTRLDESCLN_6_CKMIN_R(0) |
>> >> > +		     DCU_CTRLDESCLN_6_CKMIN_G(0) |
>> >> > +		     DCU_CTRLDESCLN_6_CKMIN_B(0));
>> >> > +	regmap_write(fsl_dev->regmap, DCU_CTRLDESCLN_7(index), 0);
>> >> > +	regmap_write(fsl_dev->regmap, DCU_CTRLDESCLN_8(index),
>> >> > +		     DCU_CTRLDESCLN_8_FG_FCOLOR(0));
>> >> > +	regmap_write(fsl_dev->regmap, DCU_CTRLDESCLN_9(index),
>> >> > +		     DCU_CTRLDESCLN_9_BG_BCOLOR(0));
>> >> > +	if (of_device_is_compatible(fsl_dev->np, "fsl,ls1021a-dcu"))
>> >> > +		regmap_write(fsl_dev->regmap, DCU_CTRLDESCLN_10(index),
>> >> > +			     DCU_CTRLDESCLN_10_POST_SKIP(0) |
>> >> > +			     DCU_CTRLDESCLN_10_PRE_SKIP(0));
>> >> > +	regmap_update_bits(fsl_dev->regmap, DCU_DCU_MODE,
>> >> > +			   DCU_MODE_DCU_MODE_MASK,
>> >> > +			   DCU_MODE_DCU_MODE(DCU_MODE_NORMAL));
>> >> > +	regmap_write(fsl_dev->regmap, DCU_UPDATE_MODE,
>> >> DCU_UPDATE_MODE_READREG);
>> >> > +}
>> >> > +
>> >> > +int fsl_dcu_drm_plane_disable(struct drm_plane *plane)
>> >> > +{
>> >> > +	return 0;
>> >> > +}
>> >> > +
>> >> > +void fsl_dcu_drm_plane_destroy(struct drm_plane *plane)
>> >> > +{
>> >> > +	fsl_dcu_drm_plane_disable(plane);
>> >> > +	drm_plane_cleanup(plane);
>> >> > +}
>> >> > +
>> >> > +static const uint32_t fsl_dcu_drm_plane_formats[] = {
>> >> > +	DRM_FORMAT_RGB565,
>> >> > +	DRM_FORMAT_RGB888,
>> >> > +	DRM_FORMAT_ARGB8888,
>> >> > +	DRM_FORMAT_ARGB4444,
>> >> > +	DRM_FORMAT_ARGB1555,
>> >> > +	DRM_FORMAT_YUV422,
>> >> > +};
>> >> > +
>> >> > +static const struct drm_plane_funcs fsl_dcu_drm_plane_funcs = {
>> >> > +	.update_plane = drm_atomic_helper_update_plane,
>> >> > +	.disable_plane = drm_atomic_helper_disable_plane,
>> >> > +	.destroy = fsl_dcu_drm_plane_destroy,
>> >> > +	.atomic_duplicate_state =
>> drm_atomic_helper_plane_duplicate_state,
>> >> > +	.atomic_destroy_state = drm_atomic_helper_plane_destroy_state,
>> >> > +	.reset = drm_atomic_helper_plane_reset,
>> >> > +};
>> >> > +
>> >> > +static const struct drm_plane_helper_funcs
>> >> fsl_dcu_drm_plane_helper_funcs = {
>> >> > +	.prepare_fb = fsl_dcu_drm_plane_prepare_fb,
>> >> > +	.cleanup_fb = fsl_dcu_drm_plane_cleanup_fb,
>> >> > +	.atomic_check = fsl_dcu_drm_plane_atomic_check,
>> >> > +	.atomic_update = fsl_dcu_drm_plane_atomic_update,
>> >> > +	.atomic_disable = fsl_dcu_drm_plane_atomic_disable,
>> >> > +};
>> >> > +
>> >> > +struct drm_plane *fsl_dcu_drm_primary_create_plane(struct drm_device
>> >> *dev)
>> >> > +{
>> >> > +	struct drm_plane *primary;
>> >> > +	int ret;
>> >> > +
>> >> > +	primary = kzalloc(sizeof(*primary), GFP_KERNEL);
>> >> > +	if (!primary) {
>> >> > +		DRM_DEBUG_KMS("Failed to allocate primary plane\n");
>> >> > +		return NULL;
>> >> > +	}
>> >> > +
>> >> > +	/* possible_crtc's will be filled in later by crtc_init */
>> >> > +	ret = drm_universal_plane_init(dev, primary, 0,
>> >> > +				       &fsl_dcu_drm_plane_funcs,
>> >> > +				       fsl_dcu_drm_plane_formats,
>> >> > +				       ARRAY_SIZE(fsl_dcu_drm_plane_formats),
>> >> > +				       DRM_PLANE_TYPE_PRIMARY);
>> >> > +	if (ret) {
>> >> > +		kfree(primary);
>> >> > +		primary = NULL;
>> >> > +	}
>> >> > +	drm_plane_helper_add(primary, &fsl_dcu_drm_plane_helper_funcs);
>> >> > +
>> >> > +	return primary;
>> >> > +}
>> >> > diff --git a/drivers/gpu/drm/fsl/fsl_dcu_drm_plane.h
>> >> > b/drivers/gpu/drm/fsl/fsl_dcu_drm_plane.h
>> >> > new file mode 100644
>> >> > index 0000000..ccbfa61
>> >> > --- /dev/null
>> >> > +++ b/drivers/gpu/drm/fsl/fsl_dcu_drm_plane.h
>> >> > @@ -0,0 +1,23 @@
>> >> > +/*
>> >> > + * Copyright 2015 Freescale Semiconductor, Inc.
>> >> > + *
>> >> > + * Freescale DCU drm device driver
>> >> > + *
>> >> > + * 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 __FSL_DCU_DRM_PLANE_H__
>> >> > +#define __FSL_DCU_DRM_PLANE_H__
>> >> > +
>> >> > +struct fsl_dcu_drm_device;
>> >> > +struct fsl_dcu_drm_plane {
>> >> > +	struct drm_plane plane;
>> >> > +	unsigned int index;
>> >> > +};
>> >> > +
>> >> > +struct drm_plane *fsl_dcu_drm_primary_create_plane(struct drm_device
>> >> *dev);
>> >> > +
>> >> > +#endif /* __FSL_DCU_DRM_PLANE_H__ */

--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Jianwei.Wang@freescale.com April 15, 2015, 10 a.m. UTC | #6
Hi Stefan,

> -----Original Message-----
> From: Stefan Agner [mailto:stefan@agner.ch]
> Sent: Wednesday, April 08, 2015 3:57 PM
> To: Wang Jianwei-B52261
> Cc: Wood Scott-B07421; airlied@linux.ie; dri-devel@lists.freedesktop.org;
> devicetree@vger.kernel.org; Xiubo Li; Wang Huan-B18965; linux-
> kernel@vger.kernel.org; Jin Zhengxiong-R64188; linux-arm-
> kernel@lists.infradead.org
> Subject: RE: [PATCH v3 1/4] drm/layerscape: Add Freescale DCU DRM driver
> 
> On 2015-04-08 09:17, Jianwei.Wang@freescale.com wrote:
> > Hi Stefan,
> >
> >> -----Original Message-----
> >> From: Stefan Agner [mailto:stefan@agner.ch]
> >> Sent: Tuesday, April 07, 2015 8:12 PM
> >> To: Wang Jianwei-B52261
> >> Cc: Wood Scott-B07421; airlied@linux.ie; dri-
> devel@lists.freedesktop.org;
> >> devicetree@vger.kernel.org; Xiubo Li; Wang Huan-B18965; linux-
> >> kernel@vger.kernel.org; Jin Zhengxiong-R64188; linux-arm-
> >> kernel@lists.infradead.org
> >> Subject: RE: [PATCH v3 1/4] drm/layerscape: Add Freescale DCU DRM
> driver
> >>
> >> Hi Jianwei,
> >>
> >> On 2015-04-07 08:44, Jianwei.Wang@freescale.com wrote:
> >> > Hi Stefan,
> >> >
> >> > Thank you for your review and testing on Vybrid F610 device. This
> driver
> >> > just implement the basic functions and it only support the exported
> >> > framebuffer access. Some DRM interfaces are not implemented now. So
> your
> >> > test result is normal. I will implement these interfaces with patches
> >> soon
> >> > afterwards. I don't plan to add new features for the initial version
> >> driver,
> >> > otherwise it will be a long term for this version.
> >> >
> >> > I tested on ls1021a using TFT panel, there are no flickers on the
> screen
> >> > when inserting a USB HID device. I will do more test if time permits.
> >> >
> >> > By the way, could please give me some guidance on how X-Server use
> DRM
> >> > Interface directly? Do you have some papers or webpage about this?
> >>
> >> I'm using the modesetting X.org driver. Lots of distributions ship that
> >> driver as a package (e.g. xserver-xorg-video-modesetting in Debian, or
> >> xf86-video-modesetting in OpenEmbedded). Since 1.17 this driver has
> even
> >> been included into the main source tree of Xorg X-Server
> >>
> (http://cgit.freedesktop.org/xorg/xserver/tree/hw/xfree86/drivers/modesett
> >> ing)
> >>
> >> This driver is using KMS/DRM interface and should work well for
> >> un-accelerated graphic devices. This is a a much nicer way to use X.org
> >> on top of a DRM driver, since it avoids going through the legacy fbdev
> >> interface. The man page shows how to use it:
> >> http://linux.die.net/man/4/modesetting
> >>
> >> So, when the driver is installed, it is just choosing that driver in
> >> xorg.conf:
> >>
> >> Section "Device"
> >>         Identifier      "dcu"
> >>         Driver          "modesetting"
> >> EndSection
> >>
> >
> > Thank you for your guidance.
> >
> >> Some more comments below...
> >>
> >> >
> >> > My reply below...
> >> >
> >> >>
> >> >> Hi Jianwei,
> >> >>
> >> >> The driver worked on a Vybrid VF610 device using the exported
> >> >> framebuffer. However, when using X-Server through the DRM interface
> >> >> directly (by using the modesetting driver) I get just a black screen
> so
> >> >> far, still investigating the reason. What user-space interfaces did
> you
> >> >> test?
> >> >>
> >> >> When using the FB device and insert a USB HID device, I get some
> >> >> flickers on the screen. I didn't had those on the dcufb driver, did
> you
> >> >> notice something like this too? Probably related to the resolution,
> I'm
> >> >> using VGA resolution.
> >> >>
> >> >> Some comments below.
> >> >>
> >> >>
> >> >> On 2015-03-26 06:37, Jianwei Wang wrote:
> >> >> > This patch add support for Two Dimensional Animation and
> Compositing
> >> >> > Engine (2D-ACE) on the Freescale SoCs.
> >> >> >
> >> >> > 2D-ACE is a Freescale display controller. 2D-ACE describes
> >> >> > the functionality of the module extremely well its name is a value
> >> >> > that cannot be used as a token in programming languages.
> >> >> > Instead the valid token "DCU" is used to tag the register names
> and
> >> >> > function names.
> >> >> >
> >> >> > The Display Controller Unit (DCU) module is a system master that
> >> >> > fetches graphics stored in internal or external memory and
> displays
> >> >> > them on a TFT LCD panel. A wide range of panel sizes is supported
> >> >> > and the timing of the interface signals is highly configurable.
> >> >> > Graphics are read directly from memory and then blended in real-
> time,
> >> >> > which allows for dynamic content creation with minimal CPU
> >> >> > intervention.
> >> >> >
> >> >> > The features:
> >> >> > (1) Full RGB888 output to TFT LCD panel.
> >> >> > (2) For the current LCD panel, WQVGA "480x272" is supported.
> >> >> > (3) Blending of each pixel using up to 4 source layers
> >> >> > dependent on size of panel.
> >> >>
> >> >> modetest only shows one layer currently...
> >> >
> >> > Yes, only one plane and one framebuffer were created now, others
> >> > maybe create as user requirement or create all when initializing,
> >> > I'm not sure now. This describe the hardware feature
> >> >
> >> >>
> >> >> > (4) Each graphic layer can be placed with one pixel resolution
> >> >> > in either axis.
> >> >> > (5) Each graphic layer support RGB565 and RGB888 direct colors
> >> >> > without alpha channel
> >> >> > and BGRA8888 direct colors with an alpha channel.
> >> >>
> >> >> The array fsl_dcu_drm_plane_formats below shows more formats, does
> this
> >> >> commit log needs updating?
> >> >>
> >> >
> >> > I agree with your suggestion, I will update this commit log
> >> >
> >> >> > (6) Each graphic layer support alpha blending with 8-bit
> >> >> > resolution.
> >> >> >
> >> >> > This is a simplified version, only one primary plane, one
> >> >> > framebuffer created for fbdev, one crtc, one connector for
> >> >> > TFT LCD panel, an encoder.
> >> >> >
> >> >> > Signed-off-by: Alison Wang <b18965@freescale.com>
> >> >> > Signed-off-by: Xiubo Li <lixiubo@cmss.chinamobile.com>
> >> >> > Signed-off-by: Jianwei Wang <b52261@freescale.com>
> >> >> > ---
> >> >> >
> >> >> > Changed in V3:
> >> >> >
> >> >> > - Test driver on Vybrid board and add compatible string
> >> >> > - Remove unused functions
> >> >> > - set default crtc for encoder
> >> >> > - replace legacy functions with atomic help functions
> >> >> > - Set the unique name of the DRM device
> >> >> > - Implement irq handle function for vblank interrupt
> >> >> >
> >> >> > Changed in v2:
> >> >> > - Add atomic support
> >> >> > - Modify bindings file
> >> >> > - Rename node for compatibility
> >> >> > - Move platform related code out for compatibility
> >> >> >
> >> >> >  .../devicetree/bindings/drm/fsl/fsl,dcu.txt        |  50 ++++
> >> >> >  drivers/gpu/drm/Kconfig                            |   2 +
> >> >> >  drivers/gpu/drm/Makefile                           |   1 +
> >> >> >  drivers/gpu/drm/fsl/Kconfig                        |  17 ++
> >> >> >  drivers/gpu/drm/fsl/Makefile                       |   8 +
> >> >> >  drivers/gpu/drm/fsl/fsl_dcu_drm_connector.c        | 193
> >> ++++++++++++
> >> >> >  drivers/gpu/drm/fsl/fsl_dcu_drm_connector.h        |  30 ++
> >> >> >  drivers/gpu/drm/fsl/fsl_dcu_drm_crtc.c             | 165
> ++++++++++
> >> >> >  drivers/gpu/drm/fsl/fsl_dcu_drm_crtc.h             |  26 ++
> >> >> >  drivers/gpu/drm/fsl/fsl_dcu_drm_drv.c              | 331
> >> >> +++++++++++++++++++++
> >> >> >  drivers/gpu/drm/fsl/fsl_dcu_drm_drv.h              | 210
> >> +++++++++++++
> >> >> >  drivers/gpu/drm/fsl/fsl_dcu_drm_fbdev.c            |  26 ++
> >> >> >  drivers/gpu/drm/fsl/fsl_dcu_drm_kms.c              |  42 +++
> >> >> >  drivers/gpu/drm/fsl/fsl_dcu_drm_kms.h              |  17 ++
> >> >> >  drivers/gpu/drm/fsl/fsl_dcu_drm_plane.c            | 192
> >> ++++++++++++
> >> >> >  drivers/gpu/drm/fsl/fsl_dcu_drm_plane.h            |  23 ++
> >> >> >  16 files changed, 1333 insertions(+)
> >> >> >  create mode 100644
> >> >> Documentation/devicetree/bindings/drm/fsl/fsl,dcu.txt
> >> >> >  create mode 100644 drivers/gpu/drm/fsl/Kconfig
> >> >> >  create mode 100644 drivers/gpu/drm/fsl/Makefile
> >> >> >  create mode 100644 drivers/gpu/drm/fsl/fsl_dcu_drm_connector.c
> >> >> >  create mode 100644 drivers/gpu/drm/fsl/fsl_dcu_drm_connector.h
> >> >> >  create mode 100644 drivers/gpu/drm/fsl/fsl_dcu_drm_crtc.c
> >> >> >  create mode 100644 drivers/gpu/drm/fsl/fsl_dcu_drm_crtc.h
> >> >> >  create mode 100644 drivers/gpu/drm/fsl/fsl_dcu_drm_drv.c
> >> >> >  create mode 100644 drivers/gpu/drm/fsl/fsl_dcu_drm_drv.h
> >> >> >  create mode 100644 drivers/gpu/drm/fsl/fsl_dcu_drm_fbdev.c
> >> >> >  create mode 100644 drivers/gpu/drm/fsl/fsl_dcu_drm_kms.c
> >> >> >  create mode 100644 drivers/gpu/drm/fsl/fsl_dcu_drm_kms.h
> >> >> >  create mode 100644 drivers/gpu/drm/fsl/fsl_dcu_drm_plane.c
> >> >> >  create mode 100644 drivers/gpu/drm/fsl/fsl_dcu_drm_plane.h
> >> >> >
> >> >> > diff --git a/Documentation/devicetree/bindings/drm/fsl/fsl,dcu.txt
> >> >> > b/Documentation/devicetree/bindings/drm/fsl/fsl,dcu.txt
> >> >> > new file mode 100644
> >> >> > index 0000000..bdc7d5b
> >> >> > --- /dev/null
> >> >> > +++ b/Documentation/devicetree/bindings/drm/fsl/fsl,dcu.txt
> >> >> > @@ -0,0 +1,50 @@
> >> >> > +Device Tree bindings for Freescale DCU DRM Driver
> >> >> > +
> >> >> > +Required properties:
> >> >> > +- compatible:           Should be one of
> >> >> > +	* "fsl,ls1021a-dcu".
> >> >> > +	* "fsl,vf610-dcu".
> >> >>
> >> >> In the Vybrid reference manual, that IP is denoted as "DCU4". Any
> >> reason
> >> >> why you left out the DCU version? Is this different for LS1021a? On
> the
> >> >> other hand, with the SoC in the name, the IP should be specified
> clear
> >> >> enough.
> >> >>
> >> >
> >> > In the LS1021A reference manual, no DCU version related words. I
> asked
> >> > previous DCU owner, she told me that LS1021A use DCU5 and she also
> point
> >> > out that the same DCU version there may be differences between
> different
> >> > SoCs. So I named compatible string with SoC name.
> >>
> >> Ok, I'm fine with that, thx for the background information.
> >>
> >> >
> >> >> > +- reg:                  Address and length of the register set
> for
> >> dcu.
> >> >> > +- clocks:               From common clock binding: handle to dcu
> >> clock.
> >> >> > +- clock-names:          From common clock binding: Shall be "dcu".
> >> >> > +- display:              The phandle to display node.
> >> >> > +
> >> >> > +Required properties:
> >> >> > +- bits-per-pixel:       <16> for RGB565,
> >> >> > +			<24> for RGB888,
> >> >> > +			<32> for RGB8888.
> >> >> > +
> >> >> > +Required timing node for dispplay sub-node:
> >> >> > +- display-timings:      Refer to binding doc display-timing.txt
> for
> >> >> details.
> >> >> > +
> >> >> > +Examples:
> >> >> > +dcu: dcu@2ce0000 {
> >> >> > +	compatible = "fsl,ls1021a-dcu";
> >> >> > +	reg = <0x0 0x2ce0000 0x0 0x10000>;
> >> >> > +	clocks = <&platform_clk 0>;
> >> >> > +	clock-names = "dcu";
> >> >> > +	big-endian;
> >> >> > +	display = <&display>;
> >> >> > +
> >> >> > +	display: display@0 {
> >> >> > +		bits-per-pixel = <24>;
> >> >> > +
> >> >> > +		display-timings {
> >> >> > +			native-mode = <&timing0>;
> >> >> > +			timing0: nl4827hc19 {
> >> >> > +				clock-frequency = <10870000>;
> >> >> > +				hactive = <480>;
> >> >> > +				vactive = <272>;
> >> >> > +				hback-porch = <2>;
> >> >> > +				hfront-porch = <2>;
> >> >> > +				vback-porch = <1>;
> >> >> > +				vfront-porch = <1>;
> >> >> > +				hsync-len = <41>;
> >> >> > +				vsync-len = <2>;
> >> >> > +				hsync-active = <1>;
> >> >> > +				vsync-active = <1>;
> >> >> > +			};
> >> >> > +		};
> >> >> > +	};
> >> >> > +};
> >> >> > +
> >> >> > diff --git a/drivers/gpu/drm/Kconfig b/drivers/gpu/drm/Kconfig
> >> >> > index 151a050..a6957aa 100644
> >> >> > --- a/drivers/gpu/drm/Kconfig
> >> >> > +++ b/drivers/gpu/drm/Kconfig
> >> >> > @@ -199,6 +199,8 @@ source "drivers/gpu/drm/bochs/Kconfig"
> >> >> >
> >> >> >  source "drivers/gpu/drm/msm/Kconfig"
> >> >> >
> >> >> > +source "drivers/gpu/drm/fsl/Kconfig"
> >> >> > +
> >> >> >  source "drivers/gpu/drm/tegra/Kconfig"
> >> >> >
> >> >> >  source "drivers/gpu/drm/panel/Kconfig"
> >> >> > diff --git a/drivers/gpu/drm/Makefile b/drivers/gpu/drm/Makefile
> >> >> > index 2c239b9..ab5b9ef 100644
> >> >> > --- a/drivers/gpu/drm/Makefile
> >> >> > +++ b/drivers/gpu/drm/Makefile
> >> >> > @@ -56,6 +56,7 @@ obj-$(CONFIG_DRM_UDL) += udl/
> >> >> >  obj-$(CONFIG_DRM_AST) += ast/
> >> >> >  obj-$(CONFIG_DRM_ARMADA) += armada/
> >> >> >  obj-$(CONFIG_DRM_ATMEL_HLCDC)	+= atmel-hlcdc/
> >> >> > +obj-$(CONFIG_DRM_FSL_DCU) += fsl/
> >> >>
> >> >> Hm, I'm wondering whether it would be a good idea to store that
> driver
> >> >> under fsl-dcu/... Any opinion?
> >> >>
> >> >
> >> > I think it is good advice, I'll think about this
> >> >
> >> >> >  obj-$(CONFIG_DRM_RCAR_DU) += rcar-du/
> >> >> >  obj-$(CONFIG_DRM_SHMOBILE) +=shmobile/
> >> >> >  obj-$(CONFIG_DRM_OMAP)	+= omapdrm/
> >> >> > diff --git a/drivers/gpu/drm/fsl/Kconfig
> >> b/drivers/gpu/drm/fsl/Kconfig
> >> >> > new file mode 100644
> >> >> > index 0000000..e4f8df0
> >> >> > --- /dev/null
> >> >> > +++ b/drivers/gpu/drm/fsl/Kconfig
> >> >> > @@ -0,0 +1,17 @@
> >> >> > +config DRM_FSL_DCU
> >> >> > +	tristate "DRM Support for Freescale DCU"
> >> >> > +	depends on DRM && OF && ARM
> >> >> > +	select DRM_KMS_HELPER
> >> >> > +	select DRM_KMS_CMA_HELPER
> >> >> > +	select VIDEOMODE_HELPERS
> >> >> > +	select BACKLIGHT_CLASS_DEVICE
> >> >> > +	select BACKLIGHT_LCD_SUPPORT
> >> >> > +	select REGMAP_MMIO
> >> >> > +	select DRM_KMS_FB_HELPER
> >> >> > +	select FB_SYS_FILLRECT
> >> >> > +	select FB_SYS_COPYAREA
> >> >> > +	select FB_SYS_IMAGEBLIT
> >> >> > +	select FB_SYS_FOPS
> >> >> > +	help
> >> >> > +	  Choose this option if you have an Freescale DCU chipset.
> >> >> > +	  If M is selected the module will be called fsl-dcu-drm.
> >> >> > diff --git a/drivers/gpu/drm/fsl/Makefile
> >> b/drivers/gpu/drm/fsl/Makefile
> >> >> > new file mode 100644
> >> >> > index 0000000..5f74aee
> >> >> > --- /dev/null
> >> >> > +++ b/drivers/gpu/drm/fsl/Makefile
> >> >> > @@ -0,0 +1,8 @@
> >> >> > +fsl-dcu-drm-y := fsl_dcu_drm_drv.o \
> >> >> > +	       fsl_dcu_drm_kms.o \
> >> >> > +	       fsl_dcu_drm_connector.o \
> >> >> > +	       fsl_dcu_drm_plane.o \
> >> >> > +	       fsl_dcu_drm_crtc.o \
> >> >> > +	       fsl_dcu_drm_fbdev.o \
> >> >> > +
> >> >> > +obj-$(CONFIG_DRM_FSL_DCU)	+= fsl-dcu-drm.o
> >> >> > diff --git a/drivers/gpu/drm/fsl/fsl_dcu_drm_connector.c
> >> >> > b/drivers/gpu/drm/fsl/fsl_dcu_drm_connector.c
> >> >> > new file mode 100644
> >> >> > index 0000000..4610647
> >> >> > --- /dev/null
> >> >> > +++ b/drivers/gpu/drm/fsl/fsl_dcu_drm_connector.c
> >> >> > @@ -0,0 +1,193 @@
> >> >> > +/*
> >> >> > + * Copyright 2015 Freescale Semiconductor, Inc.
> >> >> > + *
> >> >> > + * Freescale DCU drm device driver
> >> >> > + *
> >> >> > + * This program is free software; you can redistribute it and/or
> >> modify
> >> >> > + * it under the terms of the GNU General Public License as
> published
> >> by
> >> >> > + * the Free Software Foundation; either version 2 of the License,
> or
> >> >> > + * (at your option) any later version.
> >> >> > + */
> >> >> > +
> >> >> > +#include <linux/backlight.h>
> >> >> > +
> >> >> > +#include <drm/drmP.h>
> >> >> > +#include <drm/drm_atomic_helper.h>
> >> >> > +#include <video/of_display_timing.h>
> >> >> > +
> >> >> > +#include "fsl_dcu_drm_drv.h"
> >> >> > +#include "fsl_dcu_drm_connector.h"
> >> >> > +
> >> >> > +static void fsl_dcu_drm_encoder_dpms(struct drm_encoder *encoder,
> >> int
> >> >> mode)
> >> >> > +{
> >> >> > +}
> >> >> > +
> >> >> > +static void fsl_dcu_drm_encoder_mode_prepare(struct drm_encoder
> >> >> *encoder)
> >> >> > +{
> >> >> > +}
> >> >> > +
> >> >> > +static void fsl_dcu_drm_encoder_mode_set(struct drm_encoder
> *encoder,
> >> >> > +					 struct drm_display_mode *mode,
> >> >> > +					 struct drm_display_mode
> >> *adjusted_mode)
> >> >> > +{
> >> >> > +}
> >> >> > +
> >> >> > +static void fsl_dcu_drm_encoder_mode_commit(struct drm_encoder
> >> *encoder)
> >> >> > +{
> >> >> > +}
> >> >> > +
> >> >> > +static void fsl_dcu_drm_encoder_disable(struct drm_encoder
> *encoder)
> >> >> > +{
> >> >> > +}
> >> >> > +
> >> >> > +static int
> >> >> > +fsl_dcu_drm_encoder_atomic_check(struct drm_encoder *encoder,
> >> >> > +				 struct drm_crtc_state *crtc_state,
> >> >> > +				 struct drm_connector_state *conn_state)
> >> >> > +{
> >> >> > +	return 0;
> >> >> > +}
> >> >> > +
> >> >> > +static void fsl_dcu_drm_encoder_destroy(struct drm_encoder
> *encoder)
> >> >> > +{
> >> >> > +	drm_encoder_cleanup(encoder);
> >> >> > +}
> >> >> > +
> >> >> > +static const struct drm_encoder_helper_funcs encoder_helper_funcs
> =
> >> {
> >> >> > +	.dpms = fsl_dcu_drm_encoder_dpms,
> >> >> > +	.prepare = fsl_dcu_drm_encoder_mode_prepare,
> >> >> > +	.commit = fsl_dcu_drm_encoder_mode_commit,
> >> >> > +	.mode_set = fsl_dcu_drm_encoder_mode_set,
> >> >> > +	.disable = fsl_dcu_drm_encoder_disable,
> >> >> > +	.atomic_check = fsl_dcu_drm_encoder_atomic_check,
> >> >> > +};
> >> >> > +
> >> >> > +static const struct drm_encoder_funcs encoder_funcs = {
> >> >> > +	.destroy = fsl_dcu_drm_encoder_destroy,
> >> >> > +};
> >> >> > +
> >> >> > +int fsl_dcu_drm_encoder_create(struct fsl_dcu_drm_device *fsl_dev,
> >> >> > +			       struct fsl_dcu_drm_crtc *crtc)
> >> >> > +{
> >> >> > +	struct drm_encoder *encoder = &fsl_dev->encoder;
> >> >> > +	int ret;
> >> >> > +
> >> >> > +	ret = drm_encoder_init(fsl_dev->ddev, encoder, &encoder_funcs,
> >> >> > +			       DRM_MODE_ENCODER_LVDS);
> >> >> > +	if (ret < 0)
> >> >> > +		return ret;
> >> >> > +
> >> >> > +	drm_encoder_helper_add(encoder, &encoder_helper_funcs);
> >> >> > +	encoder->crtc = &crtc->crtc;
> >> >> > +
> >> >> > +	return 0;
> >> >> > +}
> >> >> > +
> >> >> > +#define to_fsl_dcu_connector(connector) \
> >> >> > +	container_of(connector, struct fsl_dcu_drm_connector,
> >> connector)
> >> >> > +
> >> >> > +static int fsl_dcu_drm_connector_get_modes(struct drm_connector
> >> >> *connector)
> >> >> > +{
> >> >> > +	struct drm_device *dev = connector->dev;
> >> >> > +	struct device_node *display_np, *np = dev->dev->of_node;
> >> >> > +	struct drm_display_mode *mode = drm_mode_create(connector-
> >> >dev);
> >> >> > +	int num_modes = 0;
> >> >> > +
> >> >> > +	if (np) {
> >> >> > +		display_np = of_parse_phandle(np, "display", 0);
> >> >> > +		if (!display_np) {
> >> >> > +			dev_err(dev->dev, "failed to find display
> >> phandle\n");
> >> >> > +			return num_modes;
> >> >> > +		}
> >> >> > +		of_get_drm_display_mode(display_np, mode,
> >> OF_USE_NATIVE_MODE);
> >> >> > +		mode->type |= DRM_MODE_TYPE_DRIVER |
> >> DRM_MODE_TYPE_PREFERRED,
> >> >> > +		drm_mode_probed_add(connector, mode);
> >> >> > +		num_modes++;
> >> >> > +	}
> >> >> > +
> >> >> > +	return num_modes;
> >> >> > +}
> >> >> > +
> >> >> > +static int fsl_dcu_drm_connector_mode_valid(struct drm_connector
> >> >> *connector,
> >> >> > +					    struct drm_display_mode *mode)
> >> >> > +{
> >> >> > +	return MODE_OK;
> >> >> > +}
> >> >> > +
> >> >> > +static struct drm_encoder *
> >> >> > +fsl_dcu_drm_connector_best_encoder(struct drm_connector
> *connector)
> >> >> > +{
> >> >> > +	struct fsl_dcu_drm_connector *fsl_con =
> >> >> to_fsl_dcu_connector(connector);
> >> >> > +
> >> >> > +	return fsl_con->encoder;
> >> >> > +}
> >> >> > +
> >> >> > +static void fsl_dcu_drm_connector_destroy(struct drm_connector
> >> >> *connector)
> >> >> > +{
> >> >> > +	drm_connector_unregister(connector);
> >> >> > +	drm_connector_cleanup(connector);
> >> >> > +}
> >> >> > +
> >> >> > +static enum drm_connector_status
> >> >> > +fsl_dcu_drm_connector_detect(struct drm_connector *connector,
> bool
> >> >> force)
> >> >> > +{
> >> >> > +	return connector_status_connected;
> >> >> > +}
> >> >> > +
> >> >> > +static const struct drm_connector_funcs
> fsl_dcu_drm_connector_funcs
> >> = {
> >> >> > +	.dpms = drm_atomic_helper_connector_dpms,
> >> >> > +	.reset = drm_atomic_helper_connector_reset,
> >> >> > +	.detect = fsl_dcu_drm_connector_detect,
> >> >> > +	.fill_modes = drm_helper_probe_single_connector_modes,
> >> >> > +	.destroy = fsl_dcu_drm_connector_destroy,
> >> >> > +	.atomic_duplicate_state =
> >> >> drm_atomic_helper_connector_duplicate_state,
> >> >> > +	.atomic_destroy_state =
> >> drm_atomic_helper_connector_destroy_state,
> >> >> > +};
> >> >> > +
> >> >> > +static const struct drm_connector_helper_funcs
> >> connector_helper_funcs =
> >> >> {
> >> >> > +	.get_modes = fsl_dcu_drm_connector_get_modes,
> >> >> > +	.mode_valid = fsl_dcu_drm_connector_mode_valid,
> >> >> > +	.best_encoder = fsl_dcu_drm_connector_best_encoder,
> >> >> > +};
> >> >> > +
> >> >> > +int fsl_dcu_drm_connector_create(struct fsl_dcu_drm_device
> *fsl_dev,
> >> >> > +				 struct drm_encoder *encoder)
> >> >> > +{
> >> >> > +	struct drm_connector *connector = &fsl_dev-
> >> >connector.connector;
> >> >> > +	int ret;
> >> >> > +
> >> >> > +	fsl_dev->connector.encoder = encoder;
> >> >> > +
> >> >> > +	connector->display_info.width_mm = 0;
> >> >> > +	connector->display_info.height_mm = 0;
> >> >> > +
> >> >> > +	ret = drm_connector_init(fsl_dev->ddev, connector,
> >> >> > +				 &fsl_dcu_drm_connector_funcs,
> >> >> > +				 DRM_MODE_CONNECTOR_LVDS);
> >> >> > +	if (ret < 0)
> >> >> > +		return ret;
> >> >> > +
> >> >> > +	connector->dpms = DRM_MODE_DPMS_OFF;
> >> >> > +	drm_connector_helper_add(connector, &connector_helper_funcs);
> >> >> > +	ret = drm_connector_register(connector);
> >> >> > +	if (ret < 0)
> >> >> > +		goto err_cleanup;
> >> >> > +
> >> >> > +	ret = drm_mode_connector_attach_encoder(connector, encoder);
> >> >> > +	if (ret < 0)
> >> >> > +		goto err_sysfs;
> >> >> > +
> >> >> > +	connector->encoder = encoder;
> >> >> > +
> >> >> > +	drm_object_property_set_value
> >> >> > +		(&connector->base, fsl_dev->ddev-
> >> >mode_config.dpms_property,
> >> >> > +		DRM_MODE_DPMS_OFF);
> >> >> > +
> >> >> > +	return 0;
> >> >> > +
> >> >> > +err_sysfs:
> >> >> > +	drm_connector_unregister(connector);
> >> >> > +err_cleanup:
> >> >> > +	drm_connector_cleanup(connector);
> >> >> > +	return ret;
> >> >> > +}
> >> >> > diff --git a/drivers/gpu/drm/fsl/fsl_dcu_drm_connector.h
> >> >> > b/drivers/gpu/drm/fsl/fsl_dcu_drm_connector.h
> >> >> > new file mode 100644
> >> >> > index 0000000..bbf6d38
> >> >> > --- /dev/null
> >> >> > +++ b/drivers/gpu/drm/fsl/fsl_dcu_drm_connector.h
> >> >> > @@ -0,0 +1,30 @@
> >> >> > +/*
> >> >> > + * Copyright 2015 Freescale Semiconductor, Inc.
> >> >> > + *
> >> >> > + * Freescale DCU drm device driver
> >> >> > + *
> >> >> > + * 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 __FSL_DCU_DRM_CONNECTOR_H__
> >> >> > +#define __FSL_DCU_DRM_CONNECTOR_H__
> >> >> > +
> >> >> > +#include <drm/drmP.h>
> >> >> > +#include <drm/drm_crtc.h>
> >> >> > +#include "fsl_dcu_drm_crtc.h"
> >> >> > +
> >> >> > +struct fsl_dcu_drm_device;
> >> >> > +struct fsl_dcu_drm_connector {
> >> >> > +	struct drm_connector connector;
> >> >> > +	struct drm_encoder *encoder;
> >> >> > +};
> >> >> > +
> >> >> > +int fsl_dcu_drm_encoder_create(struct fsl_dcu_drm_device *fsl_dev,
> >> >> > +			       struct fsl_dcu_drm_crtc *crtc);
> >> >> > +int fsl_dcu_drm_connector_create(struct fsl_dcu_drm_device
> *fsl_dev,
> >> >> > +				 struct drm_encoder *encoder);
> >> >> > +
> >> >> > +#endif /* __FSL_DCU_DRM_CONNECTOR_H__ */
> >> >> > diff --git a/drivers/gpu/drm/fsl/fsl_dcu_drm_crtc.c
> >> >> > b/drivers/gpu/drm/fsl/fsl_dcu_drm_crtc.c
> >> >> > new file mode 100644
> >> >> > index 0000000..076e273
> >> >> > --- /dev/null
> >> >> > +++ b/drivers/gpu/drm/fsl/fsl_dcu_drm_crtc.c
> >> >> > @@ -0,0 +1,165 @@
> >> >> > +/*
> >> >> > + * Copyright 2015 Freescale Semiconductor, Inc.
> >> >> > + *
> >> >> > + * Freescale DCU drm device driver
> >> >> > + *
> >> >> > + * This program is free software; you can redistribute it and/or
> >> modify
> >> >> > + * it under the terms of the GNU General Public License as
> published
> >> by
> >> >> > + * the Free Software Foundation; either version 2 of the License,
> or
> >> >> > + * (at your option) any later version.
> >> >> > + */
> >> >> > +
> >> >> > +#include <linux/regmap.h>
> >> >> > +#include <linux/clk.h>
> >> >> > +
> >> >> > +#include <drm/drmP.h>
> >> >> > +#include <drm/drm_atomic.h>
> >> >> > +#include <drm/drm_atomic_helper.h>
> >> >> > +#include <drm/drm_crtc.h>
> >> >> > +
> >> >> > +#include "fsl_dcu_drm_crtc.h"
> >> >> > +#include "fsl_dcu_drm_drv.h"
> >> >> > +#include "fsl_dcu_drm_plane.h"
> >> >> > +
> >> >> > +#define to_fsl_dcu_crtc(c)	container_of(c, struct
> >> fsl_dcu_drm_crtc,
> >> >> crtc)
> >> >> > +
> >> >> > +void fsl_dcu_drm_crtc_suspend(struct drm_crtc *crtc)
> >> >> > +{
> >> >> > +}
> >> >> > +
> >> >> > +static void fsl_dcu_drm_crtc_mode_set_nofb(struct drm_crtc *crtc)
> >> >> > +{
> >> >> > +	struct drm_device *dev = crtc->dev;
> >> >> > +	struct fsl_dcu_drm_device *fsl_dev = dev->dev_private;
> >> >> > +	struct drm_display_mode *mode = &crtc->state->mode;
> >> >> > +	uint32_t hbp, hfp, hsw, vbp, vfp, vsw, div, index;
> >> >> > +
> >> >> > +	DBG(": set mode: %d:\"%s\" %d %d %d %d %d %d %d %d %d %d 0x%x
> >> 0x%x",
> >> >> > +	    mode->base.id, mode->name,
> >> >> > +	    mode->vrefresh, mode->clock,
> >> >> > +	    mode->hdisplay, mode->hsync_start,
> >> >> > +	    mode->hsync_end, mode->htotal,
> >> >> > +	    mode->vdisplay, mode->vsync_start,
> >> >> > +	    mode->vsync_end, mode->vtotal,
> >> >> > +	    mode->type, mode->flags);
> >> >> > +
> >> >> > +	index = drm_crtc_index(crtc);
> >> >> > +	div = (uint32_t)clk_get_rate(fsl_dev->clk) / mode->clock /
> >> 1000;
> >> >> > +
> >> >> > +	/* Configure timings: */
> >> >> > +	hbp = mode->htotal - mode->hsync_end;
> >> >> > +	hfp = mode->hsync_start - mode->hdisplay;
> >> >> > +	hsw = mode->hsync_end - mode->hsync_start;
> >> >> > +	vbp = mode->vtotal - mode->vsync_end;
> >> >> > +	vfp = mode->vsync_start - mode->vdisplay;
> >> >> > +	vsw = mode->vsync_end - mode->vsync_start;
> >> >> > +
> >> >> > +	regmap_write(fsl_dev->regmap, DCU_HSYN_PARA,
> >> >> > +		     DCU_HSYN_PARA_BP(hbp) |
> >> >> > +		     DCU_HSYN_PARA_PW(hsw) |
> >> >> > +		     DCU_HSYN_PARA_FP(hfp));
> >> >> > +	regmap_write(fsl_dev->regmap, DCU_VSYN_PARA,
> >> >> > +		     DCU_VSYN_PARA_BP(vbp) |
> >> >> > +		     DCU_VSYN_PARA_PW(vsw) |
> >> >> > +		     DCU_VSYN_PARA_FP(vfp));
> >> >> > +	regmap_write(fsl_dev->regmap, DCU_DISP_SIZE,
> >> >> > +		     DCU_DISP_SIZE_DELTA_Y(mode->vdisplay) |
> >> >> > +		     DCU_DISP_SIZE_DELTA_X(mode->hdisplay));
> >> >> > +	regmap_write(fsl_dev->regmap, DCU_DIV_RATIO, div);
> >> >> > +	regmap_write(fsl_dev->regmap, DCU_UPDATE_MODE,
> >> >> DCU_UPDATE_MODE_READREG);
> >> >> > +}
> >> >> > +
> >> >> > +static bool fsl_dcu_drm_crtc_mode_fixup(struct drm_crtc *crtc,
> >> >> > +					const struct drm_display_mode *mode,
> >> >> > +					struct drm_display_mode *adjusted_mode)
> >> >> > +{
> >> >> > +	return true;
> >> >> > +}
> >> >> > +
> >> >> > +static void fsl_dcu_drm_crtc_prepare(struct drm_crtc *crtc)
> >> >> > +{
> >> >> > +}
> >> >> > +
> >> >> > +/* Now enable the clocks, plane, pipe, and connectors that we set
> up.
> >> >> */
> >> >> > +static void fsl_dcu_drm_crtc_mode_commit(struct drm_crtc *crtc)
> >> >> > +{
> >> >> > +}
> >> >> > +
> >> >> > +static int fsl_dcu_drm_crtc_atomic_check(struct drm_crtc *crtc,
> >> >> > +					 struct drm_crtc_state *state)
> >> >> > +{
> >> >> > +	return 0;
> >> >> > +}
> >> >> > +
> >> >> > +static void fsl_dcu_drm_crtc_atomic_begin(struct drm_crtc *crtc)
> >> >> > +{
> >> >> > +}
> >> >> > +
> >> >> > +static void fsl_dcu_drm_crtc_atomic_flush(struct drm_crtc *crtc)
> >> >> > +{
> >> >> > +}
> >> >> > +
> >> >> > +static void fsl_dcu_drm_disable_crtc(struct drm_crtc *crtc)
> >> >> > +{
> >> >> > +}
> >> >> > +
> >> >> > +static const struct drm_crtc_funcs fsl_dcu_drm_crtc_funcs = {
> >> >> > +	.page_flip = drm_atomic_helper_page_flip,
> >> >> > +	.set_config = drm_atomic_helper_set_config,
> >> >> > +	.destroy = drm_crtc_cleanup,
> >> >> > +	.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 void fsl_dcu_drm_crtc_dpms(struct drm_crtc *crtc, int mode)
> >> >> > +{
> >> >> > +}
> >> >> > +
> >> >> > +static const struct drm_crtc_helper_funcs
> >> fsl_dcu_drm_crtc_helper_funcs
> >> >> = {
> >> >> > +	.disable = fsl_dcu_drm_disable_crtc,
> >> >> > +	.mode_fixup = fsl_dcu_drm_crtc_mode_fixup,
> >> >> > +	.mode_set = drm_helper_crtc_mode_set,
> >> >> > +	.mode_set_nofb = fsl_dcu_drm_crtc_mode_set_nofb,
> >> >> > +	.mode_set_base = drm_helper_crtc_mode_set_base,
> >> >> > +	.prepare = fsl_dcu_drm_crtc_prepare,
> >> >> > +	.commit = fsl_dcu_drm_crtc_mode_commit,
> >> >> > +	.atomic_check = fsl_dcu_drm_crtc_atomic_check,
> >> >> > +	.atomic_begin = fsl_dcu_drm_crtc_atomic_begin,
> >> >> > +	.atomic_flush = fsl_dcu_drm_crtc_atomic_flush,
> >> >> > +	.dpms = fsl_dcu_drm_crtc_dpms,
> >> >> > +};
> >> >> > +
> >> >> > +int fsl_dcu_drm_crtc_create(struct fsl_dcu_drm_device *fsl_dev)
> >> >> > +{
> >> >> > +	struct drm_plane *primary;
> >> >> > +	struct drm_crtc *crtc = &fsl_dev->crtc.crtc;
> >> >> > +	int ret;
> >> >> > +
> >>
> >>
> >> I hit an issue on some Vybrid devices because the planes have not been
> >> properly initialized. It seems that initialization of planes is
> required
> >> for Vybrid, something like this was also part of the DCU fbdev driver
> >> submitted by Alison Wang:
> >>
> >> +#define DCU_TOTAL_LAYER_NUM    64
> >>  int fsl_dcu_drm_crtc_create(struct fsl_dcu_drm_device *fsl_dev)
> >>  {
> >>         struct drm_plane *primary;
> >>         struct drm_crtc *crtc = &fsl_dev->crtc.crtc;
> >>         int ret;
> >> +       int i;
> >> +
> >> +       for (i = 1; i < DCU_TOTAL_LAYER_NUM; i++) {
> >> +               regmap_write(fsl_dev->regmap, DCU_CTRLDESCLN_1(i), 0);
> >> +               regmap_write(fsl_dev->regmap, DCU_CTRLDESCLN_2(i), 0);
> >> +               regmap_write(fsl_dev->regmap, DCU_CTRLDESCLN_3(i), 0);
> >> +               regmap_write(fsl_dev->regmap, DCU_CTRLDESCLN_4(i), 0);
> >> +               regmap_write(fsl_dev->regmap, DCU_CTRLDESCLN_5(i), 0);
> >> +               regmap_write(fsl_dev->regmap, DCU_CTRLDESCLN_6(i), 0);
> >> +               regmap_write(fsl_dev->regmap, DCU_CTRLDESCLN_7(i), 0);
> >> +               regmap_write(fsl_dev->regmap, DCU_CTRLDESCLN_8(i), 0);
> >> +               regmap_write(fsl_dev->regmap, DCU_CTRLDESCLN_9(i), 0);
> >> +       }
> >> +       regmap_write(fsl_dev->regmap, DCU_UPDATE_MODE,
> >> DCU_UPDATE_MODE_READREG);
> >>
> >>         fsl_dev->crtc.dpms = DRM_MODE_DPMS_OFF;
> >>
> >>
> >> Not sure if this is required for ls1021a too...
> >>
> >
> > I have tested that there is no influence on ls1021a whether doing this
> > initialization.
> > If it is a mast for Vybrid device, I will add layers initialization.
> 
> Thanks for including this, really appreciated.
> 
> There is nothing specified in the RM, but I found this Technical
> Overview slide deck:
> http://www.freescale.com/files/training/doc/dwf/DWF13_AMF_IND_T0847.pdf
> 
> Slide 58 states that the layers are not initialized. Also, the fb driver
> did the same, and the Kernel crashes on some hardware without this
> initialization, hence I guess for Vybrid its really required.
> 
> If it is not needed for LS1021a, you could also make it conditional for
> the Vybrid compatibility string.
> 
> >
> >>
> >> >> > +	fsl_dev->crtc.dpms = DRM_MODE_DPMS_OFF;
> >> >> > +
> >> >> > +	primary = fsl_dcu_drm_primary_create_plane(fsl_dev->ddev);
> >> >> > +	ret = drm_crtc_init_with_planes(fsl_dev->ddev, crtc, primary,
> >> NULL,
> >> >> > +					&fsl_dcu_drm_crtc_funcs);
> >> >> > +	if (ret < 0)
> >> >> > +		return ret;
> >> >> > +
> >> >> > +	drm_crtc_helper_add(crtc, &fsl_dcu_drm_crtc_helper_funcs);
> >> >> > +
> >> >> > +	regmap_write(fsl_dev->regmap, DCU_SYN_POL,
> >> >> > +		     DCU_SYN_POL_INV_VS_LOW | DCU_SYN_POL_INV_HS_LOW);
> >> >> > +	regmap_write(fsl_dev->regmap, DCU_BGND, DCU_BGND_R(0) |
> >> >> > +		     DCU_BGND_G(0) | DCU_BGND_B(0));
> >> >> > +	regmap_write(fsl_dev->regmap, DCU_DCU_MODE,
> >> >> > +		     DCU_MODE_BLEND_ITER(1) | DCU_MODE_RASTER_EN);
> >> >> > +	regmap_write(fsl_dev->regmap, DCU_THRESHOLD,
> >> >> > +		     DCU_THRESHOLD_LS_BF_VS(BF_VS_VAL) |
> >> >> > +		     DCU_THRESHOLD_OUT_BUF_HIGH(BUF_MAX_VAL) |
> >> >> > +		     DCU_THRESHOLD_OUT_BUF_LOW(BUF_MIN_VAL));
> >> >> > +	regmap_update_bits(fsl_dev->regmap, DCU_DCU_MODE,
> >> >> > +			   DCU_MODE_DCU_MODE_MASK,
> >> >> > +			   DCU_MODE_DCU_MODE(DCU_MODE_OFF));
> >> >> > +	regmap_write(fsl_dev->regmap, DCU_UPDATE_MODE,
> >> >> DCU_UPDATE_MODE_READREG);
> >> >> > +
> >> >> > +	return 0;
> >> >> > +}
> >> >> > diff --git a/drivers/gpu/drm/fsl/fsl_dcu_drm_crtc.h
> >> >> > b/drivers/gpu/drm/fsl/fsl_dcu_drm_crtc.h
> >> >> > new file mode 100644
> >> >> > index 0000000..d44b564
> >> >> > --- /dev/null
> >> >> > +++ b/drivers/gpu/drm/fsl/fsl_dcu_drm_crtc.h
> >> >> > @@ -0,0 +1,26 @@
> >> >> > +/*
> >> >> > + * Copyright 2015 Freescale Semiconductor, Inc.
> >> >> > + *
> >> >> > + * Freescale DCU drm device driver
> >> >> > + *
> >> >> > + * 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 __FSL_DCU_DRM_CRTC_H__
> >> >> > +#define __FSL_DCU_DRM_CRTC_H__
> >> >> > +
> >> >> > +#include <drm/drmP.h>
> >> >> > +#include <drm/drm_crtc.h>
> >> >> > +
> >> >> > +struct fsl_dcu_drm_device;
> >> >> > +struct fsl_dcu_drm_crtc {
> >> >> > +	struct drm_crtc crtc;
> >> >> > +	int dpms;
> >> >> > +};
> >> >> > +
> >> >> > +int fsl_dcu_drm_crtc_create(struct fsl_dcu_drm_device *fsl_dev);
> >> >> > +
> >> >> > +#endif /* __FSL_DCU_DRM_CRTC_H__ */
> >> >> > diff --git a/drivers/gpu/drm/fsl/fsl_dcu_drm_drv.c
> >> >> > b/drivers/gpu/drm/fsl/fsl_dcu_drm_drv.c
> >> >> > new file mode 100644
> >> >> > index 0000000..d4a559a
> >> >> > --- /dev/null
> >> >> > +++ b/drivers/gpu/drm/fsl/fsl_dcu_drm_drv.c
> >> >> > @@ -0,0 +1,331 @@
> >> >> > +/*
> >> >> > + * Copyright 2015 Freescale Semiconductor, Inc.
> >> >> > + *
> >> >> > + * Freescale DCU drm device driver
> >> >> > + *
> >> >> > + * This program is free software; you can redistribute it and/or
> >> modify
> >> >> > + * it under the terms of the GNU General Public License as
> published
> >> by
> >> >> > + * the Free Software Foundation; either version 2 of the License,
> or
> >> >> > + * (at your option) any later version.
> >> >> > + */
> >> >> > +
> >> >> > +#include <linux/clk.h>
> >> >> > +#include <linux/io.h>
> >> >> > +#include <linux/mm.h>
> >> >> > +#include <linux/module.h>
> >> >> > +#include <linux/of_platform.h>
> >> >> > +#include <linux/platform_device.h>
> >> >> > +#include <linux/pm.h>
> >> >> > +#include <linux/pm_runtime.h>
> >> >> > +#include <linux/regmap.h>
> >> >> > +
> >> >> > +#include <drm/drmP.h>
> >> >> > +#include <linux/fsl/dcu.h>
> >> >>
> >> >> This file seems to be missing in that patch.
> >> >>
> >> >
> >> > This file in patch 2/4, It's LS1021A platform related code.
> >> >
> >>
> >> This is not allowed in the kernel world: Each commit need to represent
> a
> >> complete change in the sense of being compileable and runnable. This is
> >> required to bisect kernel issues. Git bisect helps isolate issues by
> >> selecting random commits. If someone is using git bisect, and git
> >> happens to choose to test this exact revision, the developer will sit
> in
> >> front of a broken kernel. Whenever possible, we try to avoid that.
> >>
> >> In this case, you can easily avoid that by moving patch 2/4 in front of
> >> this patch. Then the file will be there when the driver is using it.
> >>
> >
> > I will adjust the sequence properly. Thank you again, I learn a lot from
> you.
> >
> >> However, as I already stated in v2 of the patchset, I don't think that
> >> direct calls into arch are the right solution to enable the pixel clock.
> >> To me, that looks like a clock gate which asks for the common clock
> >> framework being used, e.g. the clk-gate driver:
> >> http://lxr.free-electrons.com/source/drivers/clk/clk-gate.c
> >>
> >> The DCU clock gates in Vybrid use this driver too, see:
> >> http://lxr.free-electrons.com/source/arch/arm/mach-imx/clk-vf610.c#L317
> >>
> >> --
> >> Stefan
> >>
> >
> > Hum... I think this clock may not as you considered. This clock is pixel
> clock
> > rather than DCU module clock. Enable it means allow the clock export
> > to the pixel pin
> > from DCU module. Common clock framework isn't suitable for managing this
> clock.
> 
> The common clock framework slide deck of Free Electrons explicitly
> state:
> ..."Controlling clocks is useful for:" ... "time reference: to compute a
> baud-rate or a pixel clock for
> example".
> http://elinux.org/images/b/b8/Elc2013_Clement.pdf
> 
> I think the common clock framework is perfectly fine for this use case.
> You can also assign two clocks to a module, and use something like:
> 
> clocks = <&platform_clk 0>, <&scfg_clk DCU0_PIXELCLOCK>;
> clock-names = "ipg", "pixclk;
> 
> The IPU of i.MX6 also uses the clock framework to get the pixel clocks
> assigned:
> http://lxr.free-electrons.com/source/arch/arm/boot/dts/imx6q.dtsi#L154
> 
> You probably need to introduce something like clk-ls102xa.c, and export
> the clocks available from the scfg module...
> 
> --
> Stefan
> 
> 

I have looked into CCF recently. It indeed suit for pixel clock management.
I plan to implement it but not in the initial version. I will do this with
patches later, because I want to focus my thought on the DRM framework now.
I have to introduce files as you said when implementing pixel clock 
management with CCF. This may caused several weeks discuss.

I will enable the pixel clock in the driver driectly as an expedient.

--
Jianwei

> >
> > --
> > Jianwei
> >>
> >> >> > +
> >> >> > +#include "fsl_dcu_drm_drv.h"
> >> >> > +#include "fsl_dcu_drm_kms.h"
> >> >> > +
> >> >> > +static int fsl_dcu_unload(struct drm_device *dev)
> >> >> > +{
> >> >> > +	drm_mode_config_cleanup(dev);
> >> >> > +	drm_vblank_cleanup(dev);
> >> >> > +	drm_irq_uninstall(dev);
> >> >> > +
> >> >> > +	dev->dev_private = NULL;
> >> >> > +
> >> >> > +	return 0;
> >> >> > +}
> >> >> > +
> >> >> > +static struct regmap_config fsl_dcu_regmap_config = {
> >> >> > +	.reg_bits = 32,
> >> >> > +	.reg_stride = 4,
> >> >> > +	.val_bits = 32,
> >> >> > +};
> >> >> > +
> >> >> > +static int fsl_dcu_bypass_tcon(struct fsl_dcu_drm_device *fsl_dev,
> >> >> > +			       struct device_node *np)
> >> >> > +{
> >> >> > +	struct device_node *tcon_np;
> >> >> > +	struct platform_device *pdev;
> >> >> > +	struct clk *tcon_clk;
> >> >> > +	struct resource *res;
> >> >> > +	void __iomem *base;
> >> >> > +
> >> >> > +	tcon_np = of_parse_phandle(np, "tcon-controller", 0);
> >> >> > +	if (!tcon_np)
> >> >> > +		return -EINVAL;
> >> >> > +
> >> >> > +	pdev = of_find_device_by_node(tcon_np);
> >> >> > +	if (!pdev)
> >> >> > +		return -EINVAL;
> >> >> > +
> >> >> > +	tcon_clk = devm_clk_get(&pdev->dev, "tcon");
> >> >> > +	if (IS_ERR(tcon_clk))
> >> >> > +		return PTR_ERR(tcon_clk);
> >> >> > +	clk_prepare_enable(tcon_clk);
> >> >>
> >> >> You enable the clock explicitly...
> >> >>
> >> >> > +
> >> >> > +	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> >> >> > +	if (!res)
> >> >> > +		return -ENODEV;
> >> >> > +
> >> >> > +	base = devm_ioremap_resource(&pdev->dev, res);
> >> >> > +	if (IS_ERR(base))
> >> >> > +		return PTR_ERR(base);
> >> >> > +
> >> >> > +	fsl_dev->tcon_regmap = devm_regmap_init_mmio_clk(&pdev->dev,
> >> >> > +			"tcon", base, &fsl_dcu_regmap_config);
> >> >>
> >> >> And implicitly using regmap. In a short test on Vybrid, the clock is
> >> >> actually not needed during operation, hence we could use the
> explicit
> >> >> enabling above, what do you think?
> >> >>
> >> >> Also, the clock and tcon in general currently does not get handled
> by
> >> >> suspend/resume code...
> >> >>
> >> >
> >> > OK, I'll update code here
> >> >
> >> >> > +	if (IS_ERR(fsl_dev->tcon_regmap)) {
> >> >> > +		dev_err(&pdev->dev, "regmap init failed\n");
> >> >> > +		return PTR_ERR(fsl_dev->tcon_regmap);
> >> >> > +	}
> >> >> > +
> >> >> > +	regmap_write(fsl_dev->tcon_regmap, TCON_CTRL1,
> >> TCON_BYPASS_ENABLE);
> >> >> > +	return 0;
> >> >> > +}
> >> >> > +
> >> >> > +static int fsl_dcu_drm_irq_init(struct drm_device *dev)
> >> >> > +{
> >> >> > +	struct platform_device *pdev = dev->platformdev;
> >> >> > +	struct fsl_dcu_drm_device *fsl_dev = dev->dev_private;
> >> >> > +	unsigned int int_mask;
> >> >> > +	int ret;
> >> >> > +
> >> >> > +	ret = drm_irq_install(dev, platform_get_irq(dev->platformdev,
> >> 0));
> >> >> > +	if (ret < 0)
> >> >> > +		dev_err(&pdev->dev, "failed to install IRQ handler\n");
> >> >> > +
> >> >> > +	dev->irq_enabled = true;
> >> >> > +	dev->vblank_disable_allowed = true;
> >> >> > +
> >> >> > +	regmap_write(fsl_dev->regmap, DCU_INT_STATUS, 0);
> >> >> > +	regmap_read(fsl_dev->regmap, DCU_INT_MASK, &int_mask);
> >> >> > +	regmap_write(fsl_dev->regmap, DCU_INT_MASK, int_mask &
> >> >> > +		     ~DCU_INT_MASK_VBLANK);
> >> >> > +	regmap_write(fsl_dev->regmap, DCU_UPDATE_MODE,
> >> >> DCU_UPDATE_MODE_READREG);
> >> >> > +
> >> >> > +	return 0;
> >> >> > +}
> >> >> > +
> >> >> > +static int fsl_dcu_load(struct drm_device *dev, unsigned long
> flags)
> >> >> > +{
> >> >> > +	struct platform_device *pdev = dev->platformdev;
> >> >> > +	struct fsl_dcu_drm_device *fsl_dev;
> >> >> > +	struct resource *res;
> >> >> > +	void __iomem *base;
> >> >> > +	int ret;
> >> >> > +
> >> >> > +	fsl_dev = devm_kzalloc(&pdev->dev, sizeof(*fsl_dev),
> >> GFP_KERNEL);
> >> >> > +	if (!fsl_dev)
> >> >> > +		return -ENOMEM;
> >> >> > +
> >> >> > +	fsl_dev->dev = &pdev->dev;
> >> >> > +	fsl_dev->ddev = dev;
> >> >> > +	fsl_dev->np = pdev->dev.of_node;
> >> >> > +	dev->dev_private = fsl_dev;
> >> >> > +	drm_dev_set_unique(dev, dev_name(dev->dev));
> >> >> > +
> >> >> > +	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> >> >> > +	if (!res) {
> >> >> > +		dev_err(&pdev->dev, "could not get memory IO
> >> resource\n");
> >> >> > +		return -ENODEV;
> >> >> > +	}
> >> >> > +
> >> >> > +	base = devm_ioremap_resource(&pdev->dev, res);
> >> >> > +	if (IS_ERR(base)) {
> >> >> > +		ret = PTR_ERR(base);
> >> >> > +		return ret;
> >> >> > +	}
> >> >> > +
> >> >> > +	fsl_dev->regmap = devm_regmap_init_mmio_clk(&pdev->dev, NULL,
> >> >> > +			base, &fsl_dcu_regmap_config);
> >> >> > +	if (IS_ERR(fsl_dev->regmap)) {
> >> >> > +		dev_err(&pdev->dev, "regmap init failed\n");
> >> >> > +		return PTR_ERR(fsl_dev->regmap);
> >> >> > +	}
> >> >> > +
> >> >> > +	/* Put TCON in bypass mode, so the input signals from DCU are
> >> passed
> >> >> > +	 * through TCON unchanged */
> >> >> > +	fsl_dcu_bypass_tcon(fsl_dev, fsl_dev->np);
> >> >> > +	fsl_dev->clk = devm_clk_get(&pdev->dev, "dcu");
> >> >> > +	if (IS_ERR(fsl_dev->clk)) {
> >> >> > +		ret = PTR_ERR(fsl_dev->clk);
> >> >> > +		dev_err(&pdev->dev, "could not get clock\n");
> >> >> > +		return ret;
> >> >> > +	}
> >> >> > +	clk_prepare_enable(fsl_dev->clk);
> >> >> > +	dev_set_drvdata(dev->dev, fsl_dev);
> >> >> > +
> >> >> > +	ret = fsl_dcu_drm_modeset_init(fsl_dev);
> >> >> > +	if (ret < 0) {
> >> >> > +		dev_err(&pdev->dev, "failed to initialize mode
> >> setting\n");
> >> >> > +		return ret;
> >> >> > +	}
> >> >> > +
> >> >> > +	ret = drm_vblank_init(dev, dev->mode_config.num_crtc);
> >> >> > +	if (ret < 0) {
> >> >> > +		dev_err(&pdev->dev, "failed to initialize vblank\n");
> >> >> > +		goto done;
> >> >> > +	}
> >> >> > +
> >> >> > +	ret = fsl_dcu_drm_irq_init(dev);
> >> >> > +	if (ret < 0)
> >> >> > +		goto done;
> >> >> > +
> >> >> > +	fsl_dcu_fbdev_init(dev);
> >> >> > +
> >> >> > +	return 0;
> >> >> > +done:
> >> >> > +	if (ret)
> >> >> > +		fsl_dcu_unload(dev);
> >> >> > +
> >> >> > +	return ret;
> >> >> > +}
> >> >> > +
> >> >> > +static void fsl_dcu_drm_preclose(struct drm_device *dev, struct
> >> >> drm_file *file)
> >> >> > +{
> >> >> > +	;
> >> >> > +}
> >> >> > +
> >> >> > +static irqreturn_t fsl_dcu_drm_irq(int irq, void *arg)
> >> >> > +{
> >> >> > +	struct drm_device *dev = arg;
> >> >> > +	struct fsl_dcu_drm_device *fsl_dev = dev->dev_private;
> >> >> > +	unsigned int int_status;
> >> >> > +
> >> >> > +	regmap_read(fsl_dev->regmap, DCU_INT_STATUS, &int_status);
> >> >> > +	if (int_status & DCU_INT_STATUS_VBLANK)
> >> >> > +		drm_handle_vblank(dev, 0);
> >> >> > +
> >> >> > +	regmap_write(fsl_dev->regmap, DCU_INT_STATUS, 0xffffffff);
> >> >> > +	regmap_write(fsl_dev->regmap, DCU_UPDATE_MODE,
> >> >> DCU_UPDATE_MODE_READREG);
> >> >> > +
> >> >> > +	return IRQ_HANDLED;
> >> >> > +}
> >> >> > +
> >> >> > +static int fsl_dcu_drm_enable_vblank(struct drm_device *dev, int
> >> crtc)
> >> >> > +{
> >> >> > +	return 0;
> >> >> > +}
> >> >> > +
> >> >> > +static void fsl_dcu_drm_disable_vblank(struct drm_device *dev,
> int
> >> crtc)
> >> >> > +{
> >> >> > +	;
> >> >> > +}
> >> >> > +
> >> >> > +static const struct file_operations fsl_dcu_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		= no_llseek,
> >> >> > +	.mmap		= drm_gem_cma_mmap,
> >> >> > +};
> >> >> > +
> >> >> > +static struct drm_driver fsl_dcu_drm_driver = {
> >> >> > +	.driver_features	= DRIVER_HAVE_IRQ | DRIVER_GEM |
> >> DRIVER_MODESET
> >> >> > +				| DRIVER_PRIME,
> >> >> > +	.load			= fsl_dcu_load,
> >> >> > +	.unload			= fsl_dcu_unload,
> >> >> > +	.preclose		= fsl_dcu_drm_preclose,
> >> >> > +	.irq_handler		= fsl_dcu_drm_irq,
> >> >> > +	.get_vblank_counter	= drm_vblank_count,
> >> >> > +	.enable_vblank		= fsl_dcu_drm_enable_vblank,
> >> >> > +	.disable_vblank		= fsl_dcu_drm_disable_vblank,
> >> >> > +	.gem_free_object	= drm_gem_cma_free_object,
> >> >> > +	.gem_vm_ops		= &drm_gem_cma_vm_ops,
> >> >> > +	.prime_handle_to_fd	= drm_gem_prime_handle_to_fd,
> >> >> > +	.prime_fd_to_handle	= drm_gem_prime_fd_to_handle,
> >> >> > +	.gem_prime_import	= drm_gem_prime_import,
> >> >> > +	.gem_prime_export	= drm_gem_prime_export,
> >> >> > +	.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,
> >> >> > +	.dumb_create		= drm_gem_cma_dumb_create,
> >> >> > +	.dumb_map_offset	= drm_gem_cma_dumb_map_offset,
> >> >> > +	.dumb_destroy		= drm_gem_dumb_destroy,
> >> >> > +	.fops			= &fsl_dcu_drm_fops,
> >> >> > +	.name			= "fsl-dcu-drm",
> >> >> > +	.desc			= "Freescale DCU DRM",
> >> >> > +	.date			= "20150213",
> >> >> > +	.major			= 1,
> >> >> > +	.minor			= 0,
> >> >> > +};
> >> >> > +
> >> >> > +#ifdef CONFIG_PM_SLEEP
> >> >> > +static int fsl_dcu_drm_pm_suspend(struct device *dev)
> >> >> > +{
> >> >> > +	struct fsl_dcu_drm_device *fsl_dev = dev_get_drvdata(dev);
> >> >> > +
> >> >> > +	if (of_device_is_compatible(fsl_dev->np, "fsl,ls1021a-dcu"))
> >> >> > +		dcu_pixclk_disable();
> >> >> > +
> >> >> > +	drm_kms_helper_poll_disable(fsl_dev->ddev);
> >> >> > +	fsl_dcu_drm_crtc_suspend(&fsl_dev->crtc);
> >> >>
> >> >> I get
> >> >>
> >> >> drivers/gpu/drm/fsl/fsl_dcu_drm_drv.c: In function
> >> >> 'fsl_dcu_drm_pm_suspend':
> >> >> drivers/gpu/drm/fsl/fsl_dcu_drm_drv.c:270:2: error: implicit
> >> declaration
> >> >> of function 'fsl_dcu_drm_crtc_suspend'
> >> >> [-Werror=implicit-function-declaration]
> >> >>   fsl_dcu_drm_crtc_suspend(&fsl_dev->crtc);
> >> >>   ^
> >> >> drivers/gpu/drm/fsl/fsl_dcu_drm_drv.c: In function
> >> >> 'fsl_dcu_drm_pm_resume':
> >> >> drivers/gpu/drm/fsl/fsl_dcu_drm_drv.c:280:2: error: implicit
> >> declaration
> >> >> of function 'fsl_dcu_drm_crtc_resume'
> >> >> [-Werror=implicit-function-declaration]
> >> >>   fsl_dcu_drm_crtc_resume(&fsl_dev->crtc);
> >> >>   ^
> >> >>
> >> >> The function fsl_dcu_drm_crtc_suspend seems to be part of
> >> >> fsl_dcu_drm_crtc.c, but is empty. While the other is missing
> >> >> completely... Please fix/remove as appropriate.
> >> >>
> >> >
> >> > OK, I'll fix it
> >> >
> >> > Regards
> >> > Jianwei
> >> >> > +
> >> >> > +	return 0;
> >> >> > +}
> >> >> > +
> >> >> > +static int fsl_dcu_drm_pm_resume(struct device *dev)
> >> >> > +{
> >> >> > +	struct fsl_dcu_drm_device *fsl_dev = dev_get_drvdata(dev);
> >> >> > +
> >> >> > +	drm_modeset_lock_all(fsl_dev->ddev);
> >> >> > +	fsl_dcu_drm_crtc_resume(&fsl_dev->crtc);
> >> >> > +	drm_modeset_unlock_all(fsl_dev->ddev);
> >> >> > +	drm_kms_helper_poll_enable(fsl_dev->ddev);
> >> >> > +
> >> >> > +	if (of_device_is_compatible(fsl_dev->np, "fsl,ls1021a-dcu"))
> >> >> > +		dcu_pixclk_enable();
> >> >> > +
> >> >> > +	return 0;
> >> >> > +}
> >> >> > +#endif
> >> >> > +
> >> >> > +static const struct dev_pm_ops fsl_dcu_drm_pm_ops = {
> >> >> > +	SET_SYSTEM_SLEEP_PM_OPS(fsl_dcu_drm_pm_suspend,
> >> >> fsl_dcu_drm_pm_resume)
> >> >> > +};
> >> >> > +
> >> >> > +static int fsl_dcu_drm_probe(struct platform_device *pdev)
> >> >> > +{
> >> >> > +	return drm_platform_init(&fsl_dcu_drm_driver, pdev);
> >> >> > +}
> >> >> > +
> >> >> > +static int fsl_dcu_drm_remove(struct platform_device *pdev)
> >> >> > +{
> >> >> > +	struct fsl_dcu_drm_device *fsl_dev =
> >> platform_get_drvdata(pdev);
> >> >> > +
> >> >> > +	drm_put_dev(fsl_dev->ddev);
> >> >> > +
> >> >> > +	return 0;
> >> >> > +}
> >> >> > +
> >> >> > +static const struct of_device_id fsl_dcu_of_match[] = {
> >> >> > +		{ .compatible = "fsl,ls1021a-dcu", },
> >> >> > +		{ .compatible = "fsl,vf610-dcu", },
> >> >> > +		{ },
> >> >> > +};
> >> >> > +MODULE_DEVICE_TABLE(of, fsl_dcu_of_match);
> >> >> > +
> >> >> > +static struct platform_driver fsl_dcu_drm_platform_driver = {
> >> >> > +	.probe		= fsl_dcu_drm_probe,
> >> >> > +	.remove		= fsl_dcu_drm_remove,
> >> >> > +	.driver		= {
> >> >> > +		.owner	= THIS_MODULE,
> >> >> > +		.name	= "fsl,dcu",
> >> >> > +		.pm	= &fsl_dcu_drm_pm_ops,
> >> >> > +		.of_match_table = fsl_dcu_of_match,
> >> >> > +	},
> >> >> > +};
> >> >> > +
> >> >> > +module_platform_driver(fsl_dcu_drm_platform_driver);
> >> >> > +
> >> >> > +MODULE_ALIAS("platform:fsl-dcu-drm");
> >> >> > +MODULE_DESCRIPTION("Freescale DCU DRM Driver");
> >> >> > +MODULE_LICENSE("GPL");
> >> >> > diff --git a/drivers/gpu/drm/fsl/fsl_dcu_drm_drv.h
> >> >> > b/drivers/gpu/drm/fsl/fsl_dcu_drm_drv.h
> >> >> > new file mode 100644
> >> >> > index 0000000..27226109
> >> >> > --- /dev/null
> >> >> > +++ b/drivers/gpu/drm/fsl/fsl_dcu_drm_drv.h
> >> >> > @@ -0,0 +1,210 @@
> >> >> > +/*
> >> >> > + * Copyright 2015 Freescale Semiconductor, Inc.
> >> >> > + *
> >> >> > + * Freescale DCU drm device driver
> >> >> > + *
> >> >> > + * 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 __FSL_DCU_DRM_DRV_H__
> >> >> > +#define __FSL_DCU_DRM_DRV_H__
> >> >> > +
> >> >> > +#include <linux/kernel.h>
> >> >> > +#include <linux/spinlock.h>
> >> >> > +#include <stddef.h>
> >> >> > +#include <drm/drm.h>
> >> >> > +#include <drm/drmP.h>
> >> >> > +#include <drm/drm_fb_helper.h>
> >> >> > +#include <drm/drm_crtc_helper.h>
> >> >> > +#include <drm/drm_gem_cma_helper.h>
> >> >> > +#include <drm/drm_fb_cma_helper.h>
> >> >> > +
> >> >> > +#include "fsl_dcu_drm_crtc.h"
> >> >> > +#include "fsl_dcu_drm_plane.h"
> >> >> > +#include "fsl_dcu_drm_connector.h"
> >> >> > +#define DRIVER_NAME			"fsl-dcu-drm"
> >> >> > +
> >> >> > +#define DCU_DCU_MODE			0x0010
> >> >> > +#define DCU_MODE_BLEND_ITER(x)		((x) << 20)
> >> >> > +#define DCU_MODE_RASTER_EN		BIT(14)
> >> >> > +#define DCU_MODE_DCU_MODE(x)		(x)
> >> >> > +#define DCU_MODE_DCU_MODE_MASK		0x03
> >> >> > +#define DCU_MODE_OFF			0
> >> >> > +#define DCU_MODE_NORMAL			1
> >> >> > +#define DCU_MODE_TEST			2
> >> >> > +#define DCU_MODE_COLORBAR		3
> >> >> > +
> >> >> > +#define DCU_BGND			0x0014
> >> >> > +#define DCU_BGND_R(x)			((x) << 16)
> >> >> > +#define DCU_BGND_G(x)			((x) << 8)
> >> >> > +#define DCU_BGND_B(x)			(x)
> >> >> > +
> >> >> > +#define DCU_DISP_SIZE			0x0018
> >> >> > +#define DCU_DISP_SIZE_DELTA_Y(x)	((x) << 16)
> >> >> > +/*Regisiter value 1/16 of horizontal resolution*/
> >> >> > +#define DCU_DISP_SIZE_DELTA_X(x)	((x) >> 4)
> >> >> > +
> >> >> > +#define DCU_HSYN_PARA			0x001c
> >> >> > +#define DCU_HSYN_PARA_BP(x)		((x) << 22)
> >> >> > +#define DCU_HSYN_PARA_PW(x)		((x) << 11)
> >> >> > +#define DCU_HSYN_PARA_FP(x)		(x)
> >> >> > +
> >> >> > +#define DCU_VSYN_PARA			0x0020
> >> >> > +#define DCU_VSYN_PARA_BP(x)		((x) << 22)
> >> >> > +#define DCU_VSYN_PARA_PW(x)		((x) << 11)
> >> >> > +#define DCU_VSYN_PARA_FP(x)		(x)
> >> >> > +
> >> >> > +#define DCU_SYN_POL			0x0024
> >> >> > +#define DCU_SYN_POL_INV_PXCK_FALL	(0 << 6)
> >> >> > +#define DCU_SYN_POL_NEG_REMAIN		(0 << 5)
> >> >> > +#define DCU_SYN_POL_INV_VS_LOW		BIT(1)
> >> >> > +#define DCU_SYN_POL_INV_HS_LOW		BIT(0)
> >> >> > +
> >> >> > +#define DCU_THRESHOLD			0x0028
> >> >> > +#define DCU_THRESHOLD_LS_BF_VS(x)	((x) << 16)
> >> >> > +#define DCU_THRESHOLD_OUT_BUF_HIGH(x)	((x) << 8)
> >> >> > +#define DCU_THRESHOLD_OUT_BUF_LOW(x)	(x)
> >> >> > +#define BF_VS_VAL			0x03
> >> >> > +#define BUF_MAX_VAL			0x78
> >> >> > +#define BUF_MIN_VAL			0x0a
> >> >> > +
> >> >> > +#define DCU_INT_STATUS			0x002C
> >> >> > +#define DCU_INT_STATUS_VSYNC		BIT(0)
> >> >> > +#define DCU_INT_STATUS_UNDRUN		BIT(1)
> >> >> > +#define DCU_INT_STATUS_LSBFVS		BIT(2)
> >> >> > +#define DCU_INT_STATUS_VBLANK		BIT(3)
> >> >> > +#define DCU_INT_STATUS_CRCREADY		BIT(4)
> >> >> > +#define DCU_INT_STATUS_CRCOVERFLOW	BIT(5)
> >> >> > +#define DCU_INT_STATUS_P1FIFOLO		BIT(6)
> >> >> > +#define DCU_INT_STATUS_P1FIFOHI		BIT(7)
> >> >> > +#define DCU_INT_STATUS_P2FIFOLO		BIT(8)
> >> >> > +#define DCU_INT_STATUS_P2FIFOHI		BIT(9)
> >> >> > +#define DCU_INT_STATUS_PROGEND		BIT(10)
> >> >> > +#define DCU_INT_STATUS_IPMERROR		BIT(11)
> >> >> > +#define DCU_INT_STATUS_LYRTRANS		BIT(12)
> >> >> > +#define DCU_INT_STATUS_DMATRANS		BIT(14)
> >> >> > +#define DCU_INT_STATUS_P3FIFOLO		BIT(16)
> >> >> > +#define DCU_INT_STATUS_P3FIFOHI		BIT(17)
> >> >> > +#define DCU_INT_STATUS_P4FIFOLO		BIT(18)
> >> >> > +#define DCU_INT_STATUS_P4FIFOHI		BIT(19)
> >> >> > +#define DCU_INT_STATUS_P1EMPTY		BIT(26)
> >> >> > +#define DCU_INT_STATUS_P2EMPTY		BIT(27)
> >> >> > +#define DCU_INT_STATUS_P3EMPTY		BIT(28)
> >> >> > +#define DCU_INT_STATUS_P4EMPTY		BIT(29)
> >> >> > +
> >> >> > +#define DCU_INT_MASK			0x0030
> >> >> > +#define DCU_INT_MASK_VSYNC		BIT(0)
> >> >> > +#define DCU_INT_MASK_UNDRUN		BIT(1)
> >> >> > +#define DCU_INT_MASK_LSBFVS		BIT(2)
> >> >> > +#define DCU_INT_MASK_VBLANK		BIT(3)
> >> >> > +#define DCU_INT_MASK_CRCREADY		BIT(4)
> >> >> > +#define DCU_INT_MASK_CRCOVERFLOW	BIT(5)
> >> >> > +#define DCU_INT_MASK_P1FIFOLO		BIT(6)
> >> >> > +#define DCU_INT_MASK_P1FIFOHI		BIT(7)
> >> >> > +#define DCU_INT_MASK_P2FIFOLO		BIT(8)
> >> >> > +#define DCU_INT_MASK_P2FIFOHI		BIT(9)
> >> >> > +#define DCU_INT_MASK_PROGEND		BIT(10)
> >> >> > +#define DCU_INT_MASK_IPMERROR		BIT(11)
> >> >> > +#define DCU_INT_MASK_LYRTRANS		BIT(12)
> >> >> > +#define DCU_INT_MASK_DMATRANS		BIT(14)
> >> >> > +#define DCU_INT_MASK_P3FIFOLO		BIT(16)
> >> >> > +#define DCU_INT_MASK_P3FIFOHI		BIT(17)
> >> >> > +#define DCU_INT_MASK_P4FIFOLO		BIT(18)
> >> >> > +#define DCU_INT_MASK_P4FIFOHI		BIT(19)
> >> >> > +#define DCU_INT_MASK_P1EMPTY		BIT(26)
> >> >> > +#define DCU_INT_MASK_P2EMPTY		BIT(27)
> >> >> > +#define DCU_INT_MASK_P3EMPTY		BIT(28)
> >> >> > +#define DCU_INT_MASK_P4EMPTY		BIT(29)
> >> >> > +
> >> >> > +#define DCU_DIV_RATIO			0x0054
> >> >> > +
> >> >> > +#define DCU_UPDATE_MODE			0x00cc
> >> >> > +#define DCU_UPDATE_MODE_MODE		BIT(31)
> >> >> > +#define DCU_UPDATE_MODE_READREG		BIT(30)
> >> >> > +
> >> >> > +#define DCU_DCFB_MAX			0x300
> >> >> > +
> >> >> > +#define DCU_CTRLDESCLN_1(x)		(0x200 + (x) * 0x40)
> >> >> > +#define DCU_CTRLDESCLN_1_HEIGHT(x)	((x) << 16)
> >> >> > +#define DCU_CTRLDESCLN_1_WIDTH(x)	(x)
> >> >> > +
> >> >> > +#define DCU_CTRLDESCLN_2(x)		(0x204 + (x) * 0x40)
> >> >> > +#define DCU_CTRLDESCLN_2_POSY(x)	((x) << 16)
> >> >> > +#define DCU_CTRLDESCLN_2_POSX(x)	(x)
> >> >> > +
> >> >> > +#define DCU_CTRLDESCLN_3(x)		(0x208 + (x) * 0x40)
> >> >> > +
> >> >> > +#define DCU_CTRLDESCLN_4(x)		(0x20c + (x) * 0x40)
> >> >> > +#define DCU_CTRLDESCLN_4_EN		BIT(31)
> >> >> > +#define DCU_CTRLDESCLN_4_TILE_EN	BIT(30)
> >> >> > +#define DCU_CTRLDESCLN_4_DATA_SEL_CLUT	BIT(29)
> >> >> > +#define DCU_CTRLDESCLN_4_SAFETY_EN	BIT(28)
> >> >> > +#define DCU_CTRLDESCLN_4_TRANS(x)	((x) << 20)
> >> >> > +#define DCU_CTRLDESCLN_4_BPP(x)		((x) << 16)
> >> >> > +#define DCU_CTRLDESCLN_4_RLE_EN		BIT(15)
> >> >> > +#define DCU_CTRLDESCLN_4_LUOFFS(x)	((x) << 4)
> >> >> > +#define DCU_CTRLDESCLN_4_BB_ON		BIT(2)
> >> >> > +#define DCU_CTRLDESCLN_4_AB(x)		(x)
> >> >> > +
> >> >> > +#define DCU_CTRLDESCLN_5(x)		(0x210 + (x) * 0x40)
> >> >> > +#define DCU_CTRLDESCLN_5_CKMAX_R(x)	((x) << 16)
> >> >> > +#define DCU_CTRLDESCLN_5_CKMAX_G(x)	((x) << 8)
> >> >> > +#define DCU_CTRLDESCLN_5_CKMAX_B(x)	(x)
> >> >> > +
> >> >> > +#define DCU_CTRLDESCLN_6(x)		(0x214 + (x) * 0x40)
> >> >> > +#define DCU_CTRLDESCLN_6_CKMIN_R(x)	((x) << 16)
> >> >> > +#define DCU_CTRLDESCLN_6_CKMIN_G(x)	((x) << 8)
> >> >> > +#define DCU_CTRLDESCLN_6_CKMIN_B(x)	(x)
> >> >> > +
> >> >> > +#define DCU_CTRLDESCLN_7(x)		(0x218 + (x) * 0x40)
> >> >> > +#define DCU_CTRLDESCLN_7_TILE_VER(x)	((x) << 16)
> >> >> > +#define DCU_CTRLDESCLN_7_TILE_HOR(x)	(x)
> >> >> > +
> >> >> > +#define DCU_CTRLDESCLN_8(x)		(0x21c + (x) * 0x40)
> >> >> > +#define DCU_CTRLDESCLN_8_FG_FCOLOR(x)	(x)
> >> >> > +
> >> >> > +#define DCU_CTRLDESCLN_9(x)		(0x220 + (x) * 0x40)
> >> >> > +#define DCU_CTRLDESCLN_9_BG_BCOLOR(x)	(x)
> >> >> > +
> >> >> > +#define DCU_CTRLDESCLN_10(x)		(0x224 + (x) * 0x40)
> >> >> > +#define DCU_CTRLDESCLN_10_POST_SKIP(x)	((x) << 16)
> >> >> > +#define DCU_CTRLDESCLN_10_PRE_SKIP(x)	(x)
> >> >> > +
> >> >> > +#define FSL_DCU_RGB565			4
> >> >> > +#define FSL_DCU_RGB888			5
> >> >> > +#define FSL_DCU_ARGB8888		6
> >> >> > +#define FSL_DCU_ARGB1555		11
> >> >> > +#define FSL_DCU_ARGB4444		12
> >> >> > +#define FSL_DCU_YUV422			14
> >> >> > +
> >> >> > +#define TCON_CTRL1			0x0000
> >> >> > +#define TCON_BYPASS_ENABLE		BIT(29)
> >> >> > +
> >> >> > +#define DBG(fmt, ...) DRM_DEBUG(fmt"\n", ##__VA_ARGS__)
> >> >> > +
> >> >> > +struct clk;
> >> >> > +struct device;
> >> >> > +struct drm_device;
> >> >> > +
> >> >> > +struct fsl_dcu_drm_device {
> >> >> > +	struct device *dev;
> >> >> > +	struct device_node *np;
> >> >> > +	struct regmap *regmap;
> >> >> > +	struct regmap *tcon_regmap;
> >> >> > +	unsigned int irq;
> >> >> > +	struct clk *clk;
> >> >> > +	/*protects hardware register*/
> >> >> > +	spinlock_t irq_lock;
> >> >> > +	struct drm_device *ddev;
> >> >> > +	struct drm_fbdev_cma *fbdev;
> >> >> > +	struct fsl_dcu_drm_crtc crtc;
> >> >> > +	struct drm_encoder encoder;
> >> >> > +	struct fsl_dcu_drm_connector connector;
> >> >> > +};
> >> >> > +
> >> >> > +void fsl_dcu_fbdev_init(struct drm_device *dev);
> >> >> > +
> >> >> > +#endif /* __FSL_DCU_DRM_DRV_H__ */
> >> >> > diff --git a/drivers/gpu/drm/fsl/fsl_dcu_drm_fbdev.c
> >> >> > b/drivers/gpu/drm/fsl/fsl_dcu_drm_fbdev.c
> >> >> > new file mode 100644
> >> >> > index 0000000..f8ef0e1
> >> >> > --- /dev/null
> >> >> > +++ b/drivers/gpu/drm/fsl/fsl_dcu_drm_fbdev.c
> >> >> > @@ -0,0 +1,26 @@
> >> >> > +/*
> >> >> > + * Copyright 2015 Freescale Semiconductor, Inc.
> >> >> > + *
> >> >> > + * 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.
> >> >> > + *
> >> >> > + * This program is distributed in the hope that it will be useful,
> >> but
> >> >> WITHOUT
> >> >> > + * ANY WARRANTY; without even the implied warranty of
> >> MERCHANTABILITY
> >> >> or
> >> >> > + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
> >> >> License for
> >> >> > + * more details.
> >> >> > + *
> >> >> > + */
> >> >> > +
> >> >> > +#include <drm/drmP.h>
> >> >> > +#include <drm/drm_fb_cma_helper.h>
> >> >> > +
> >> >> > +#include "fsl_dcu_drm_drv.h"
> >> >> > +
> >> >> > +/* initialize fbdev helper */
> >> >> > +void fsl_dcu_fbdev_init(struct drm_device *dev)
> >> >> > +{
> >> >> > +	struct fsl_dcu_drm_device *fsl_dev = dev_get_drvdata(dev->dev);
> >> >> > +
> >> >> > +	fsl_dev->fbdev = drm_fbdev_cma_init(dev, 24, 1, 1);
> >> >> > +}
> >> >> > diff --git a/drivers/gpu/drm/fsl/fsl_dcu_drm_kms.c
> >> >> > b/drivers/gpu/drm/fsl/fsl_dcu_drm_kms.c
> >> >> > new file mode 100644
> >> >> > index 0000000..0de21c6
> >> >> > --- /dev/null
> >> >> > +++ b/drivers/gpu/drm/fsl/fsl_dcu_drm_kms.c
> >> >> > @@ -0,0 +1,42 @@
> >> >> > +/*
> >> >> > + * Copyright 2015 Freescale Semiconductor, Inc.
> >> >> > + *
> >> >> > + * Freescale DCU drm device driver
> >> >> > + *
> >> >> > + * 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 "fsl_dcu_drm_crtc.h"
> >> >> > +#include "fsl_dcu_drm_connector.h"
> >> >> > +#include "fsl_dcu_drm_drv.h"
> >> >> > +
> >> >> > +static const struct drm_mode_config_funcs
> >> fsl_dcu_drm_mode_config_funcs
> >> >> = {
> >> >> > +	.fb_create = drm_fb_cma_create,
> >> >> > +	.atomic_check = drm_atomic_helper_check,
> >> >> > +	.atomic_commit = drm_atomic_helper_commit,
> >> >> > +};
> >> >> > +
> >> >> > +int fsl_dcu_drm_modeset_init(struct fsl_dcu_drm_device *fsl_dev)
> >> >> > +{
> >> >> > +	drm_mode_config_init(fsl_dev->ddev);
> >> >> > +
> >> >> > +	fsl_dev->ddev->mode_config.min_width = 0;
> >> >> > +	fsl_dev->ddev->mode_config.min_height = 0;
> >> >> > +	fsl_dev->ddev->mode_config.max_width = 2031;
> >> >> > +	fsl_dev->ddev->mode_config.max_height = 2047;
> >> >> > +	fsl_dev->ddev->mode_config.funcs =
> >> &fsl_dcu_drm_mode_config_funcs;
> >> >> > +
> >> >> > +	drm_kms_helper_poll_init(fsl_dev->ddev);
> >> >> > +	fsl_dcu_drm_crtc_create(fsl_dev);
> >> >> > +	fsl_dcu_drm_encoder_create(fsl_dev, &fsl_dev->crtc);
> >> >> > +	fsl_dcu_drm_connector_create(fsl_dev, &fsl_dev->encoder);
> >> >> > +	drm_mode_config_reset(fsl_dev->ddev);
> >> >> > +
> >> >> > +	return 0;
> >> >> > +}
> >> >> > diff --git a/drivers/gpu/drm/fsl/fsl_dcu_drm_kms.h
> >> >> > b/drivers/gpu/drm/fsl/fsl_dcu_drm_kms.h
> >> >> > new file mode 100644
> >> >> > index 0000000..b9bd299
> >> >> > --- /dev/null
> >> >> > +++ b/drivers/gpu/drm/fsl/fsl_dcu_drm_kms.h
> >> >> > @@ -0,0 +1,17 @@
> >> >> > +/*
> >> >> > + * Copyright 2015 Freescale Semiconductor, Inc.
> >> >> > + *
> >> >> > + * Freescale DCU drm device driver
> >> >> > + *
> >> >> > + * 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 __FSL_DCU_DRM_KMS_H__
> >> >> > +#define __FSL_DCU_DRM_KMS_H__
> >> >> > +
> >> >> > +int fsl_dcu_drm_modeset_init(struct fsl_dcu_drm_device *fsl_dev);
> >> >> > +
> >> >> > +#endif /* __FSL_DCU_DRM_KMS_H__ */
> >> >> > diff --git a/drivers/gpu/drm/fsl/fsl_dcu_drm_plane.c
> >> >> > b/drivers/gpu/drm/fsl/fsl_dcu_drm_plane.c
> >> >> > new file mode 100644
> >> >> > index 0000000..6146e80
> >> >> > --- /dev/null
> >> >> > +++ b/drivers/gpu/drm/fsl/fsl_dcu_drm_plane.c
> >> >> > @@ -0,0 +1,192 @@
> >> >> > +/*
> >> >> > + * Copyright 2015 Freescale Semiconductor, Inc.
> >> >> > + *
> >> >> > + * Freescale DCU drm device driver
> >> >> > + *
> >> >> > + * 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_crtc.h>
> >> >> > +#include <drm/drm_crtc_helper.h>
> >> >> > +#include <drm/drm_fb_cma_helper.h>
> >> >> > +#include <drm/drm_gem_cma_helper.h>
> >> >> > +#include <linux/regmap.h>
> >> >> > +#include <drm/drm_plane_helper.h>
> >> >> > +#include <drm/drm_atomic_helper.h>
> >> >> > +
> >> >> > +#include "fsl_dcu_drm_drv.h"
> >> >> > +#include "fsl_dcu_drm_kms.h"
> >> >> > +#include "fsl_dcu_drm_plane.h"
> >> >> > +
> >> >> > +#define to_fsl_dcu_plane(plane) \
> >> >> > +	container_of(plane, struct fsl_dcu_drm_plane, plane)
> >> >> > +
> >> >> > +static int
> >> >> > +fsl_dcu_drm_plane_prepare_fb(struct drm_plane *plane,
> >> >> > +			     struct drm_framebuffer *fb,
> >> >> > +			     const struct drm_plane_state *new_state)
> >> >> > +{
> >> >> > +	return 0;
> >> >> > +}
> >> >> > +
> >> >> > +static void
> >> >> > +fsl_dcu_drm_plane_cleanup_fb(struct drm_plane *plane,
> >> >> > +			     struct drm_framebuffer *fb,
> >> >> > +			     const struct drm_plane_state *new_state)
> >> >> > +{
> >> >> > +}
> >> >> > +
> >> >> > +static int fsl_dcu_drm_plane_atomic_check(struct drm_plane *plane,
> >> >> > +					  struct drm_plane_state *state)
> >> >> > +{
> >> >> > +	return 0;
> >> >> > +}
> >> >> > +
> >> >> > +static void fsl_dcu_drm_plane_atomic_disable(struct drm_plane
> *plane,
> >> >> > +					     struct drm_plane_state *old_state)
> >> >> > +{
> >> >> > +}
> >> >> > +
> >> >> > +void fsl_dcu_drm_plane_atomic_update(struct drm_plane *plane,
> >> >> > +				     struct drm_plane_state *old_state)
> >> >> > +{
> >> >> > +	struct fsl_dcu_drm_device *fsl_dev = plane->dev->dev_private;
> >> >> > +	struct drm_plane_state *state = plane->state;
> >> >> > +	struct drm_framebuffer *fb = plane->state->fb;
> >> >> > +	u32 index, alpha, bpp;
> >> >> > +	struct drm_gem_cma_object *gem;
> >> >> > +	struct fsl_dcu_drm_plane *fsl_plane = to_fsl_dcu_plane(plane);
> >> >> > +
> >> >> > +	index = fsl_plane->index;
> >> >> > +	gem = drm_fb_cma_get_gem_obj(fb, 0);
> >> >> > +
> >> >> > +	switch (fb->pixel_format) {
> >> >> > +	case DRM_FORMAT_RGB565:
> >> >> > +		bpp = FSL_DCU_RGB565;
> >> >> > +		alpha = 0xff;
> >> >> > +		break;
> >> >> > +	case DRM_FORMAT_RGB888:
> >> >> > +		bpp = FSL_DCU_RGB888;
> >> >> > +		alpha = 0xff;
> >> >> > +		break;
> >> >> > +	case DRM_FORMAT_ARGB8888:
> >> >> > +		bpp = FSL_DCU_ARGB8888;
> >> >> > +		alpha = 0xff;
> >> >> > +		break;
> >> >> > +	case DRM_FORMAT_BGRA4444:
> >> >> > +		bpp = FSL_DCU_ARGB4444;
> >> >> > +		alpha = 0xff;
> >> >> > +		break;
> >> >> > +	case DRM_FORMAT_ARGB1555:
> >> >> > +		bpp = FSL_DCU_ARGB1555;
> >> >> > +		alpha = 0xff;
> >> >> > +		break;
> >> >> > +	case DRM_FORMAT_YUV422:
> >> >> > +		bpp = FSL_DCU_YUV422;
> >> >> > +		alpha = 0xff;
> >> >> > +		break;
> >> >> > +	default:
> >> >> > +		return;
> >> >> > +	}
> >> >> > +
> >> >> > +	regmap_write(fsl_dev->regmap, DCU_CTRLDESCLN_1(index),
> >> >> > +		     DCU_CTRLDESCLN_1_HEIGHT(state->crtc_h) |
> >> >> > +		     DCU_CTRLDESCLN_1_WIDTH(state->crtc_w));
> >> >> > +	regmap_write(fsl_dev->regmap, DCU_CTRLDESCLN_2(index),
> >> >> > +		     DCU_CTRLDESCLN_2_POSY(state->crtc_y) |
> >> >> > +		     DCU_CTRLDESCLN_2_POSX(state->crtc_x));
> >> >> > +	regmap_write(fsl_dev->regmap, DCU_CTRLDESCLN_3(index), gem-
> >> >paddr);
> >> >> > +	regmap_write(fsl_dev->regmap, DCU_CTRLDESCLN_4(index),
> >> >> > +		     DCU_CTRLDESCLN_4_EN |
> >> >> > +		     DCU_CTRLDESCLN_4_TRANS(alpha) |
> >> >> > +		     DCU_CTRLDESCLN_4_BPP(bpp) |
> >> >> > +		     DCU_CTRLDESCLN_4_AB(0));
> >> >> > +	regmap_write(fsl_dev->regmap, DCU_CTRLDESCLN_5(index),
> >> >> > +		     DCU_CTRLDESCLN_5_CKMAX_R(0xFF) |
> >> >> > +		     DCU_CTRLDESCLN_5_CKMAX_G(0xFF) |
> >> >> > +		     DCU_CTRLDESCLN_5_CKMAX_B(0xFF));
> >> >> > +	regmap_write(fsl_dev->regmap, DCU_CTRLDESCLN_6(index),
> >> >> > +		     DCU_CTRLDESCLN_6_CKMIN_R(0) |
> >> >> > +		     DCU_CTRLDESCLN_6_CKMIN_G(0) |
> >> >> > +		     DCU_CTRLDESCLN_6_CKMIN_B(0));
> >> >> > +	regmap_write(fsl_dev->regmap, DCU_CTRLDESCLN_7(index), 0);
> >> >> > +	regmap_write(fsl_dev->regmap, DCU_CTRLDESCLN_8(index),
> >> >> > +		     DCU_CTRLDESCLN_8_FG_FCOLOR(0));
> >> >> > +	regmap_write(fsl_dev->regmap, DCU_CTRLDESCLN_9(index),
> >> >> > +		     DCU_CTRLDESCLN_9_BG_BCOLOR(0));
> >> >> > +	if (of_device_is_compatible(fsl_dev->np, "fsl,ls1021a-dcu"))
> >> >> > +		regmap_write(fsl_dev->regmap, DCU_CTRLDESCLN_10(index),
> >> >> > +			     DCU_CTRLDESCLN_10_POST_SKIP(0) |
> >> >> > +			     DCU_CTRLDESCLN_10_PRE_SKIP(0));
> >> >> > +	regmap_update_bits(fsl_dev->regmap, DCU_DCU_MODE,
> >> >> > +			   DCU_MODE_DCU_MODE_MASK,
> >> >> > +			   DCU_MODE_DCU_MODE(DCU_MODE_NORMAL));
> >> >> > +	regmap_write(fsl_dev->regmap, DCU_UPDATE_MODE,
> >> >> DCU_UPDATE_MODE_READREG);
> >> >> > +}
> >> >> > +
> >> >> > +int fsl_dcu_drm_plane_disable(struct drm_plane *plane)
> >> >> > +{
> >> >> > +	return 0;
> >> >> > +}
> >> >> > +
> >> >> > +void fsl_dcu_drm_plane_destroy(struct drm_plane *plane)
> >> >> > +{
> >> >> > +	fsl_dcu_drm_plane_disable(plane);
> >> >> > +	drm_plane_cleanup(plane);
> >> >> > +}
> >> >> > +
> >> >> > +static const uint32_t fsl_dcu_drm_plane_formats[] = {
> >> >> > +	DRM_FORMAT_RGB565,
> >> >> > +	DRM_FORMAT_RGB888,
> >> >> > +	DRM_FORMAT_ARGB8888,
> >> >> > +	DRM_FORMAT_ARGB4444,
> >> >> > +	DRM_FORMAT_ARGB1555,
> >> >> > +	DRM_FORMAT_YUV422,
> >> >> > +};
> >> >> > +
> >> >> > +static const struct drm_plane_funcs fsl_dcu_drm_plane_funcs = {
> >> >> > +	.update_plane = drm_atomic_helper_update_plane,
> >> >> > +	.disable_plane = drm_atomic_helper_disable_plane,
> >> >> > +	.destroy = fsl_dcu_drm_plane_destroy,
> >> >> > +	.atomic_duplicate_state =
> >> drm_atomic_helper_plane_duplicate_state,
> >> >> > +	.atomic_destroy_state = drm_atomic_helper_plane_destroy_state,
> >> >> > +	.reset = drm_atomic_helper_plane_reset,
> >> >> > +};
> >> >> > +
> >> >> > +static const struct drm_plane_helper_funcs
> >> >> fsl_dcu_drm_plane_helper_funcs = {
> >> >> > +	.prepare_fb = fsl_dcu_drm_plane_prepare_fb,
> >> >> > +	.cleanup_fb = fsl_dcu_drm_plane_cleanup_fb,
> >> >> > +	.atomic_check = fsl_dcu_drm_plane_atomic_check,
> >> >> > +	.atomic_update = fsl_dcu_drm_plane_atomic_update,
> >> >> > +	.atomic_disable = fsl_dcu_drm_plane_atomic_disable,
> >> >> > +};
> >> >> > +
> >> >> > +struct drm_plane *fsl_dcu_drm_primary_create_plane(struct
> drm_device
> >> >> *dev)
> >> >> > +{
> >> >> > +	struct drm_plane *primary;
> >> >> > +	int ret;
> >> >> > +
> >> >> > +	primary = kzalloc(sizeof(*primary), GFP_KERNEL);
> >> >> > +	if (!primary) {
> >> >> > +		DRM_DEBUG_KMS("Failed to allocate primary plane\n");
> >> >> > +		return NULL;
> >> >> > +	}
> >> >> > +
> >> >> > +	/* possible_crtc's will be filled in later by crtc_init */
> >> >> > +	ret = drm_universal_plane_init(dev, primary, 0,
> >> >> > +				       &fsl_dcu_drm_plane_funcs,
> >> >> > +				       fsl_dcu_drm_plane_formats,
> >> >> > +				       ARRAY_SIZE(fsl_dcu_drm_plane_formats),
> >> >> > +				       DRM_PLANE_TYPE_PRIMARY);
> >> >> > +	if (ret) {
> >> >> > +		kfree(primary);
> >> >> > +		primary = NULL;
> >> >> > +	}
> >> >> > +	drm_plane_helper_add(primary, &fsl_dcu_drm_plane_helper_funcs);
> >> >> > +
> >> >> > +	return primary;
> >> >> > +}
> >> >> > diff --git a/drivers/gpu/drm/fsl/fsl_dcu_drm_plane.h
> >> >> > b/drivers/gpu/drm/fsl/fsl_dcu_drm_plane.h
> >> >> > new file mode 100644
> >> >> > index 0000000..ccbfa61
> >> >> > --- /dev/null
> >> >> > +++ b/drivers/gpu/drm/fsl/fsl_dcu_drm_plane.h
> >> >> > @@ -0,0 +1,23 @@
> >> >> > +/*
> >> >> > + * Copyright 2015 Freescale Semiconductor, Inc.
> >> >> > + *
> >> >> > + * Freescale DCU drm device driver
> >> >> > + *
> >> >> > + * 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 __FSL_DCU_DRM_PLANE_H__
> >> >> > +#define __FSL_DCU_DRM_PLANE_H__
> >> >> > +
> >> >> > +struct fsl_dcu_drm_device;
> >> >> > +struct fsl_dcu_drm_plane {
> >> >> > +	struct drm_plane plane;
> >> >> > +	unsigned int index;
> >> >> > +};
> >> >> > +
> >> >> > +struct drm_plane *fsl_dcu_drm_primary_create_plane(struct
> drm_device
> >> >> *dev);
> >> >> > +
> >> >> > +#endif /* __FSL_DCU_DRM_PLANE_H__ */

--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
diff mbox

Patch

diff --git a/Documentation/devicetree/bindings/drm/fsl/fsl,dcu.txt b/Documentation/devicetree/bindings/drm/fsl/fsl,dcu.txt
new file mode 100644
index 0000000..bdc7d5b
--- /dev/null
+++ b/Documentation/devicetree/bindings/drm/fsl/fsl,dcu.txt
@@ -0,0 +1,50 @@ 
+Device Tree bindings for Freescale DCU DRM Driver
+
+Required properties:
+- compatible:           Should be one of
+	* "fsl,ls1021a-dcu".
+	* "fsl,vf610-dcu".
+- reg:                  Address and length of the register set for dcu.
+- clocks:               From common clock binding: handle to dcu clock.
+- clock-names:          From common clock binding: Shall be "dcu".
+- display:              The phandle to display node.
+
+Required properties:
+- bits-per-pixel:       <16> for RGB565,
+			<24> for RGB888,
+			<32> for RGB8888.
+
+Required timing node for dispplay sub-node:
+- display-timings:      Refer to binding doc display-timing.txt for details.
+
+Examples:
+dcu: dcu@2ce0000 {
+	compatible = "fsl,ls1021a-dcu";
+	reg = <0x0 0x2ce0000 0x0 0x10000>;
+	clocks = <&platform_clk 0>;
+	clock-names = "dcu";
+	big-endian;
+	display = <&display>;
+
+	display: display@0 {
+		bits-per-pixel = <24>;
+
+		display-timings {
+			native-mode = <&timing0>;
+			timing0: nl4827hc19 {
+				clock-frequency = <10870000>;
+				hactive = <480>;
+				vactive = <272>;
+				hback-porch = <2>;
+				hfront-porch = <2>;
+				vback-porch = <1>;
+				vfront-porch = <1>;
+				hsync-len = <41>;
+				vsync-len = <2>;
+				hsync-active = <1>;
+				vsync-active = <1>;
+			};
+		};
+	};
+};
+
diff --git a/drivers/gpu/drm/Kconfig b/drivers/gpu/drm/Kconfig
index 151a050..a6957aa 100644
--- a/drivers/gpu/drm/Kconfig
+++ b/drivers/gpu/drm/Kconfig
@@ -199,6 +199,8 @@  source "drivers/gpu/drm/bochs/Kconfig"
 
 source "drivers/gpu/drm/msm/Kconfig"
 
+source "drivers/gpu/drm/fsl/Kconfig"
+
 source "drivers/gpu/drm/tegra/Kconfig"
 
 source "drivers/gpu/drm/panel/Kconfig"
diff --git a/drivers/gpu/drm/Makefile b/drivers/gpu/drm/Makefile
index 2c239b9..ab5b9ef 100644
--- a/drivers/gpu/drm/Makefile
+++ b/drivers/gpu/drm/Makefile
@@ -56,6 +56,7 @@  obj-$(CONFIG_DRM_UDL) += udl/
 obj-$(CONFIG_DRM_AST) += ast/
 obj-$(CONFIG_DRM_ARMADA) += armada/
 obj-$(CONFIG_DRM_ATMEL_HLCDC)	+= atmel-hlcdc/
+obj-$(CONFIG_DRM_FSL_DCU) += fsl/
 obj-$(CONFIG_DRM_RCAR_DU) += rcar-du/
 obj-$(CONFIG_DRM_SHMOBILE) +=shmobile/
 obj-$(CONFIG_DRM_OMAP)	+= omapdrm/
diff --git a/drivers/gpu/drm/fsl/Kconfig b/drivers/gpu/drm/fsl/Kconfig
new file mode 100644
index 0000000..e4f8df0
--- /dev/null
+++ b/drivers/gpu/drm/fsl/Kconfig
@@ -0,0 +1,17 @@ 
+config DRM_FSL_DCU
+	tristate "DRM Support for Freescale DCU"
+	depends on DRM && OF && ARM
+	select DRM_KMS_HELPER
+	select DRM_KMS_CMA_HELPER
+	select VIDEOMODE_HELPERS
+	select BACKLIGHT_CLASS_DEVICE
+	select BACKLIGHT_LCD_SUPPORT
+	select REGMAP_MMIO
+	select DRM_KMS_FB_HELPER
+	select FB_SYS_FILLRECT
+	select FB_SYS_COPYAREA
+	select FB_SYS_IMAGEBLIT
+	select FB_SYS_FOPS
+	help
+	  Choose this option if you have an Freescale DCU chipset.
+	  If M is selected the module will be called fsl-dcu-drm.
diff --git a/drivers/gpu/drm/fsl/Makefile b/drivers/gpu/drm/fsl/Makefile
new file mode 100644
index 0000000..5f74aee
--- /dev/null
+++ b/drivers/gpu/drm/fsl/Makefile
@@ -0,0 +1,8 @@ 
+fsl-dcu-drm-y := fsl_dcu_drm_drv.o \
+	       fsl_dcu_drm_kms.o \
+	       fsl_dcu_drm_connector.o \
+	       fsl_dcu_drm_plane.o \
+	       fsl_dcu_drm_crtc.o \
+	       fsl_dcu_drm_fbdev.o \
+
+obj-$(CONFIG_DRM_FSL_DCU)	+= fsl-dcu-drm.o
diff --git a/drivers/gpu/drm/fsl/fsl_dcu_drm_connector.c b/drivers/gpu/drm/fsl/fsl_dcu_drm_connector.c
new file mode 100644
index 0000000..4610647
--- /dev/null
+++ b/drivers/gpu/drm/fsl/fsl_dcu_drm_connector.c
@@ -0,0 +1,193 @@ 
+/*
+ * Copyright 2015 Freescale Semiconductor, Inc.
+ *
+ * Freescale DCU drm device driver
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <linux/backlight.h>
+
+#include <drm/drmP.h>
+#include <drm/drm_atomic_helper.h>
+#include <video/of_display_timing.h>
+
+#include "fsl_dcu_drm_drv.h"
+#include "fsl_dcu_drm_connector.h"
+
+static void fsl_dcu_drm_encoder_dpms(struct drm_encoder *encoder, int mode)
+{
+}
+
+static void fsl_dcu_drm_encoder_mode_prepare(struct drm_encoder *encoder)
+{
+}
+
+static void fsl_dcu_drm_encoder_mode_set(struct drm_encoder *encoder,
+					 struct drm_display_mode *mode,
+					 struct drm_display_mode *adjusted_mode)
+{
+}
+
+static void fsl_dcu_drm_encoder_mode_commit(struct drm_encoder *encoder)
+{
+}
+
+static void fsl_dcu_drm_encoder_disable(struct drm_encoder *encoder)
+{
+}
+
+static int
+fsl_dcu_drm_encoder_atomic_check(struct drm_encoder *encoder,
+				 struct drm_crtc_state *crtc_state,
+				 struct drm_connector_state *conn_state)
+{
+	return 0;
+}
+
+static void fsl_dcu_drm_encoder_destroy(struct drm_encoder *encoder)
+{
+	drm_encoder_cleanup(encoder);
+}
+
+static const struct drm_encoder_helper_funcs encoder_helper_funcs = {
+	.dpms = fsl_dcu_drm_encoder_dpms,
+	.prepare = fsl_dcu_drm_encoder_mode_prepare,
+	.commit = fsl_dcu_drm_encoder_mode_commit,
+	.mode_set = fsl_dcu_drm_encoder_mode_set,
+	.disable = fsl_dcu_drm_encoder_disable,
+	.atomic_check = fsl_dcu_drm_encoder_atomic_check,
+};
+
+static const struct drm_encoder_funcs encoder_funcs = {
+	.destroy = fsl_dcu_drm_encoder_destroy,
+};
+
+int fsl_dcu_drm_encoder_create(struct fsl_dcu_drm_device *fsl_dev,
+			       struct fsl_dcu_drm_crtc *crtc)
+{
+	struct drm_encoder *encoder = &fsl_dev->encoder;
+	int ret;
+
+	ret = drm_encoder_init(fsl_dev->ddev, encoder, &encoder_funcs,
+			       DRM_MODE_ENCODER_LVDS);
+	if (ret < 0)
+		return ret;
+
+	drm_encoder_helper_add(encoder, &encoder_helper_funcs);
+	encoder->crtc = &crtc->crtc;
+
+	return 0;
+}
+
+#define to_fsl_dcu_connector(connector) \
+	container_of(connector, struct fsl_dcu_drm_connector, connector)
+
+static int fsl_dcu_drm_connector_get_modes(struct drm_connector *connector)
+{
+	struct drm_device *dev = connector->dev;
+	struct device_node *display_np, *np = dev->dev->of_node;
+	struct drm_display_mode *mode = drm_mode_create(connector->dev);
+	int num_modes = 0;
+
+	if (np) {
+		display_np = of_parse_phandle(np, "display", 0);
+		if (!display_np) {
+			dev_err(dev->dev, "failed to find display phandle\n");
+			return num_modes;
+		}
+		of_get_drm_display_mode(display_np, mode, OF_USE_NATIVE_MODE);
+		mode->type |= DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED,
+		drm_mode_probed_add(connector, mode);
+		num_modes++;
+	}
+
+	return num_modes;
+}
+
+static int fsl_dcu_drm_connector_mode_valid(struct drm_connector *connector,
+					    struct drm_display_mode *mode)
+{
+	return MODE_OK;
+}
+
+static struct drm_encoder *
+fsl_dcu_drm_connector_best_encoder(struct drm_connector *connector)
+{
+	struct fsl_dcu_drm_connector *fsl_con = to_fsl_dcu_connector(connector);
+
+	return fsl_con->encoder;
+}
+
+static void fsl_dcu_drm_connector_destroy(struct drm_connector *connector)
+{
+	drm_connector_unregister(connector);
+	drm_connector_cleanup(connector);
+}
+
+static enum drm_connector_status
+fsl_dcu_drm_connector_detect(struct drm_connector *connector, bool force)
+{
+	return connector_status_connected;
+}
+
+static const struct drm_connector_funcs fsl_dcu_drm_connector_funcs = {
+	.dpms = drm_atomic_helper_connector_dpms,
+	.reset = drm_atomic_helper_connector_reset,
+	.detect = fsl_dcu_drm_connector_detect,
+	.fill_modes = drm_helper_probe_single_connector_modes,
+	.destroy = fsl_dcu_drm_connector_destroy,
+	.atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
+	.atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
+};
+
+static const struct drm_connector_helper_funcs connector_helper_funcs = {
+	.get_modes = fsl_dcu_drm_connector_get_modes,
+	.mode_valid = fsl_dcu_drm_connector_mode_valid,
+	.best_encoder = fsl_dcu_drm_connector_best_encoder,
+};
+
+int fsl_dcu_drm_connector_create(struct fsl_dcu_drm_device *fsl_dev,
+				 struct drm_encoder *encoder)
+{
+	struct drm_connector *connector = &fsl_dev->connector.connector;
+	int ret;
+
+	fsl_dev->connector.encoder = encoder;
+
+	connector->display_info.width_mm = 0;
+	connector->display_info.height_mm = 0;
+
+	ret = drm_connector_init(fsl_dev->ddev, connector,
+				 &fsl_dcu_drm_connector_funcs,
+				 DRM_MODE_CONNECTOR_LVDS);
+	if (ret < 0)
+		return ret;
+
+	connector->dpms = DRM_MODE_DPMS_OFF;
+	drm_connector_helper_add(connector, &connector_helper_funcs);
+	ret = drm_connector_register(connector);
+	if (ret < 0)
+		goto err_cleanup;
+
+	ret = drm_mode_connector_attach_encoder(connector, encoder);
+	if (ret < 0)
+		goto err_sysfs;
+
+	connector->encoder = encoder;
+
+	drm_object_property_set_value
+		(&connector->base, fsl_dev->ddev->mode_config.dpms_property,
+		DRM_MODE_DPMS_OFF);
+
+	return 0;
+
+err_sysfs:
+	drm_connector_unregister(connector);
+err_cleanup:
+	drm_connector_cleanup(connector);
+	return ret;
+}
diff --git a/drivers/gpu/drm/fsl/fsl_dcu_drm_connector.h b/drivers/gpu/drm/fsl/fsl_dcu_drm_connector.h
new file mode 100644
index 0000000..bbf6d38
--- /dev/null
+++ b/drivers/gpu/drm/fsl/fsl_dcu_drm_connector.h
@@ -0,0 +1,30 @@ 
+/*
+ * Copyright 2015 Freescale Semiconductor, Inc.
+ *
+ * Freescale DCU drm device driver
+ *
+ * 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 __FSL_DCU_DRM_CONNECTOR_H__
+#define __FSL_DCU_DRM_CONNECTOR_H__
+
+#include <drm/drmP.h>
+#include <drm/drm_crtc.h>
+#include "fsl_dcu_drm_crtc.h"
+
+struct fsl_dcu_drm_device;
+struct fsl_dcu_drm_connector {
+	struct drm_connector connector;
+	struct drm_encoder *encoder;
+};
+
+int fsl_dcu_drm_encoder_create(struct fsl_dcu_drm_device *fsl_dev,
+			       struct fsl_dcu_drm_crtc *crtc);
+int fsl_dcu_drm_connector_create(struct fsl_dcu_drm_device *fsl_dev,
+				 struct drm_encoder *encoder);
+
+#endif /* __FSL_DCU_DRM_CONNECTOR_H__ */
diff --git a/drivers/gpu/drm/fsl/fsl_dcu_drm_crtc.c b/drivers/gpu/drm/fsl/fsl_dcu_drm_crtc.c
new file mode 100644
index 0000000..076e273
--- /dev/null
+++ b/drivers/gpu/drm/fsl/fsl_dcu_drm_crtc.c
@@ -0,0 +1,165 @@ 
+/*
+ * Copyright 2015 Freescale Semiconductor, Inc.
+ *
+ * Freescale DCU drm device driver
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <linux/regmap.h>
+#include <linux/clk.h>
+
+#include <drm/drmP.h>
+#include <drm/drm_atomic.h>
+#include <drm/drm_atomic_helper.h>
+#include <drm/drm_crtc.h>
+
+#include "fsl_dcu_drm_crtc.h"
+#include "fsl_dcu_drm_drv.h"
+#include "fsl_dcu_drm_plane.h"
+
+#define to_fsl_dcu_crtc(c)	container_of(c, struct fsl_dcu_drm_crtc, crtc)
+
+void fsl_dcu_drm_crtc_suspend(struct drm_crtc *crtc)
+{
+}
+
+static void fsl_dcu_drm_crtc_mode_set_nofb(struct drm_crtc *crtc)
+{
+	struct drm_device *dev = crtc->dev;
+	struct fsl_dcu_drm_device *fsl_dev = dev->dev_private;
+	struct drm_display_mode *mode = &crtc->state->mode;
+	uint32_t hbp, hfp, hsw, vbp, vfp, vsw, div, index;
+
+	DBG(": set mode: %d:\"%s\" %d %d %d %d %d %d %d %d %d %d 0x%x 0x%x",
+	    mode->base.id, mode->name,
+	    mode->vrefresh, mode->clock,
+	    mode->hdisplay, mode->hsync_start,
+	    mode->hsync_end, mode->htotal,
+	    mode->vdisplay, mode->vsync_start,
+	    mode->vsync_end, mode->vtotal,
+	    mode->type, mode->flags);
+
+	index = drm_crtc_index(crtc);
+	div = (uint32_t)clk_get_rate(fsl_dev->clk) / mode->clock / 1000;
+
+	/* Configure timings: */
+	hbp = mode->htotal - mode->hsync_end;
+	hfp = mode->hsync_start - mode->hdisplay;
+	hsw = mode->hsync_end - mode->hsync_start;
+	vbp = mode->vtotal - mode->vsync_end;
+	vfp = mode->vsync_start - mode->vdisplay;
+	vsw = mode->vsync_end - mode->vsync_start;
+
+	regmap_write(fsl_dev->regmap, DCU_HSYN_PARA,
+		     DCU_HSYN_PARA_BP(hbp) |
+		     DCU_HSYN_PARA_PW(hsw) |
+		     DCU_HSYN_PARA_FP(hfp));
+	regmap_write(fsl_dev->regmap, DCU_VSYN_PARA,
+		     DCU_VSYN_PARA_BP(vbp) |
+		     DCU_VSYN_PARA_PW(vsw) |
+		     DCU_VSYN_PARA_FP(vfp));
+	regmap_write(fsl_dev->regmap, DCU_DISP_SIZE,
+		     DCU_DISP_SIZE_DELTA_Y(mode->vdisplay) |
+		     DCU_DISP_SIZE_DELTA_X(mode->hdisplay));
+	regmap_write(fsl_dev->regmap, DCU_DIV_RATIO, div);
+	regmap_write(fsl_dev->regmap, DCU_UPDATE_MODE, DCU_UPDATE_MODE_READREG);
+}
+
+static bool fsl_dcu_drm_crtc_mode_fixup(struct drm_crtc *crtc,
+					const struct drm_display_mode *mode,
+					struct drm_display_mode *adjusted_mode)
+{
+	return true;
+}
+
+static void fsl_dcu_drm_crtc_prepare(struct drm_crtc *crtc)
+{
+}
+
+/* Now enable the clocks, plane, pipe, and connectors that we set up. */
+static void fsl_dcu_drm_crtc_mode_commit(struct drm_crtc *crtc)
+{
+}
+
+static int fsl_dcu_drm_crtc_atomic_check(struct drm_crtc *crtc,
+					 struct drm_crtc_state *state)
+{
+	return 0;
+}
+
+static void fsl_dcu_drm_crtc_atomic_begin(struct drm_crtc *crtc)
+{
+}
+
+static void fsl_dcu_drm_crtc_atomic_flush(struct drm_crtc *crtc)
+{
+}
+
+static void fsl_dcu_drm_disable_crtc(struct drm_crtc *crtc)
+{
+}
+
+static const struct drm_crtc_funcs fsl_dcu_drm_crtc_funcs = {
+	.page_flip = drm_atomic_helper_page_flip,
+	.set_config = drm_atomic_helper_set_config,
+	.destroy = drm_crtc_cleanup,
+	.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 void fsl_dcu_drm_crtc_dpms(struct drm_crtc *crtc, int mode)
+{
+}
+
+static const struct drm_crtc_helper_funcs fsl_dcu_drm_crtc_helper_funcs = {
+	.disable = fsl_dcu_drm_disable_crtc,
+	.mode_fixup = fsl_dcu_drm_crtc_mode_fixup,
+	.mode_set = drm_helper_crtc_mode_set,
+	.mode_set_nofb = fsl_dcu_drm_crtc_mode_set_nofb,
+	.mode_set_base = drm_helper_crtc_mode_set_base,
+	.prepare = fsl_dcu_drm_crtc_prepare,
+	.commit = fsl_dcu_drm_crtc_mode_commit,
+	.atomic_check = fsl_dcu_drm_crtc_atomic_check,
+	.atomic_begin = fsl_dcu_drm_crtc_atomic_begin,
+	.atomic_flush = fsl_dcu_drm_crtc_atomic_flush,
+	.dpms = fsl_dcu_drm_crtc_dpms,
+};
+
+int fsl_dcu_drm_crtc_create(struct fsl_dcu_drm_device *fsl_dev)
+{
+	struct drm_plane *primary;
+	struct drm_crtc *crtc = &fsl_dev->crtc.crtc;
+	int ret;
+
+	fsl_dev->crtc.dpms = DRM_MODE_DPMS_OFF;
+
+	primary = fsl_dcu_drm_primary_create_plane(fsl_dev->ddev);
+	ret = drm_crtc_init_with_planes(fsl_dev->ddev, crtc, primary, NULL,
+					&fsl_dcu_drm_crtc_funcs);
+	if (ret < 0)
+		return ret;
+
+	drm_crtc_helper_add(crtc, &fsl_dcu_drm_crtc_helper_funcs);
+
+	regmap_write(fsl_dev->regmap, DCU_SYN_POL,
+		     DCU_SYN_POL_INV_VS_LOW | DCU_SYN_POL_INV_HS_LOW);
+	regmap_write(fsl_dev->regmap, DCU_BGND, DCU_BGND_R(0) |
+		     DCU_BGND_G(0) | DCU_BGND_B(0));
+	regmap_write(fsl_dev->regmap, DCU_DCU_MODE,
+		     DCU_MODE_BLEND_ITER(1) | DCU_MODE_RASTER_EN);
+	regmap_write(fsl_dev->regmap, DCU_THRESHOLD,
+		     DCU_THRESHOLD_LS_BF_VS(BF_VS_VAL) |
+		     DCU_THRESHOLD_OUT_BUF_HIGH(BUF_MAX_VAL) |
+		     DCU_THRESHOLD_OUT_BUF_LOW(BUF_MIN_VAL));
+	regmap_update_bits(fsl_dev->regmap, DCU_DCU_MODE,
+			   DCU_MODE_DCU_MODE_MASK,
+			   DCU_MODE_DCU_MODE(DCU_MODE_OFF));
+	regmap_write(fsl_dev->regmap, DCU_UPDATE_MODE, DCU_UPDATE_MODE_READREG);
+
+	return 0;
+}
diff --git a/drivers/gpu/drm/fsl/fsl_dcu_drm_crtc.h b/drivers/gpu/drm/fsl/fsl_dcu_drm_crtc.h
new file mode 100644
index 0000000..d44b564
--- /dev/null
+++ b/drivers/gpu/drm/fsl/fsl_dcu_drm_crtc.h
@@ -0,0 +1,26 @@ 
+/*
+ * Copyright 2015 Freescale Semiconductor, Inc.
+ *
+ * Freescale DCU drm device driver
+ *
+ * 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 __FSL_DCU_DRM_CRTC_H__
+#define __FSL_DCU_DRM_CRTC_H__
+
+#include <drm/drmP.h>
+#include <drm/drm_crtc.h>
+
+struct fsl_dcu_drm_device;
+struct fsl_dcu_drm_crtc {
+	struct drm_crtc crtc;
+	int dpms;
+};
+
+int fsl_dcu_drm_crtc_create(struct fsl_dcu_drm_device *fsl_dev);
+
+#endif /* __FSL_DCU_DRM_CRTC_H__ */
diff --git a/drivers/gpu/drm/fsl/fsl_dcu_drm_drv.c b/drivers/gpu/drm/fsl/fsl_dcu_drm_drv.c
new file mode 100644
index 0000000..d4a559a
--- /dev/null
+++ b/drivers/gpu/drm/fsl/fsl_dcu_drm_drv.c
@@ -0,0 +1,331 @@ 
+/*
+ * Copyright 2015 Freescale Semiconductor, Inc.
+ *
+ * Freescale DCU drm device driver
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <linux/clk.h>
+#include <linux/io.h>
+#include <linux/mm.h>
+#include <linux/module.h>
+#include <linux/of_platform.h>
+#include <linux/platform_device.h>
+#include <linux/pm.h>
+#include <linux/pm_runtime.h>
+#include <linux/regmap.h>
+
+#include <drm/drmP.h>
+#include <linux/fsl/dcu.h>
+
+#include "fsl_dcu_drm_drv.h"
+#include "fsl_dcu_drm_kms.h"
+
+static int fsl_dcu_unload(struct drm_device *dev)
+{
+	drm_mode_config_cleanup(dev);
+	drm_vblank_cleanup(dev);
+	drm_irq_uninstall(dev);
+
+	dev->dev_private = NULL;
+
+	return 0;
+}
+
+static struct regmap_config fsl_dcu_regmap_config = {
+	.reg_bits = 32,
+	.reg_stride = 4,
+	.val_bits = 32,
+};
+
+static int fsl_dcu_bypass_tcon(struct fsl_dcu_drm_device *fsl_dev,
+			       struct device_node *np)
+{
+	struct device_node *tcon_np;
+	struct platform_device *pdev;
+	struct clk *tcon_clk;
+	struct resource *res;
+	void __iomem *base;
+
+	tcon_np = of_parse_phandle(np, "tcon-controller", 0);
+	if (!tcon_np)
+		return -EINVAL;
+
+	pdev = of_find_device_by_node(tcon_np);
+	if (!pdev)
+		return -EINVAL;
+
+	tcon_clk = devm_clk_get(&pdev->dev, "tcon");
+	if (IS_ERR(tcon_clk))
+		return PTR_ERR(tcon_clk);
+	clk_prepare_enable(tcon_clk);
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!res)
+		return -ENODEV;
+
+	base = devm_ioremap_resource(&pdev->dev, res);
+	if (IS_ERR(base))
+		return PTR_ERR(base);
+
+	fsl_dev->tcon_regmap = devm_regmap_init_mmio_clk(&pdev->dev,
+			"tcon", base, &fsl_dcu_regmap_config);
+	if (IS_ERR(fsl_dev->tcon_regmap)) {
+		dev_err(&pdev->dev, "regmap init failed\n");
+		return PTR_ERR(fsl_dev->tcon_regmap);
+	}
+
+	regmap_write(fsl_dev->tcon_regmap, TCON_CTRL1, TCON_BYPASS_ENABLE);
+	return 0;
+}
+
+static int fsl_dcu_drm_irq_init(struct drm_device *dev)
+{
+	struct platform_device *pdev = dev->platformdev;
+	struct fsl_dcu_drm_device *fsl_dev = dev->dev_private;
+	unsigned int int_mask;
+	int ret;
+
+	ret = drm_irq_install(dev, platform_get_irq(dev->platformdev, 0));
+	if (ret < 0)
+		dev_err(&pdev->dev, "failed to install IRQ handler\n");
+
+	dev->irq_enabled = true;
+	dev->vblank_disable_allowed = true;
+
+	regmap_write(fsl_dev->regmap, DCU_INT_STATUS, 0);
+	regmap_read(fsl_dev->regmap, DCU_INT_MASK, &int_mask);
+	regmap_write(fsl_dev->regmap, DCU_INT_MASK, int_mask &
+		     ~DCU_INT_MASK_VBLANK);
+	regmap_write(fsl_dev->regmap, DCU_UPDATE_MODE, DCU_UPDATE_MODE_READREG);
+
+	return 0;
+}
+
+static int fsl_dcu_load(struct drm_device *dev, unsigned long flags)
+{
+	struct platform_device *pdev = dev->platformdev;
+	struct fsl_dcu_drm_device *fsl_dev;
+	struct resource *res;
+	void __iomem *base;
+	int ret;
+
+	fsl_dev = devm_kzalloc(&pdev->dev, sizeof(*fsl_dev), GFP_KERNEL);
+	if (!fsl_dev)
+		return -ENOMEM;
+
+	fsl_dev->dev = &pdev->dev;
+	fsl_dev->ddev = dev;
+	fsl_dev->np = pdev->dev.of_node;
+	dev->dev_private = fsl_dev;
+	drm_dev_set_unique(dev, dev_name(dev->dev));
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!res) {
+		dev_err(&pdev->dev, "could not get memory IO resource\n");
+		return -ENODEV;
+	}
+
+	base = devm_ioremap_resource(&pdev->dev, res);
+	if (IS_ERR(base)) {
+		ret = PTR_ERR(base);
+		return ret;
+	}
+
+	fsl_dev->regmap = devm_regmap_init_mmio_clk(&pdev->dev, NULL,
+			base, &fsl_dcu_regmap_config);
+	if (IS_ERR(fsl_dev->regmap)) {
+		dev_err(&pdev->dev, "regmap init failed\n");
+		return PTR_ERR(fsl_dev->regmap);
+	}
+
+	/* Put TCON in bypass mode, so the input signals from DCU are passed
+	 * through TCON unchanged */
+	fsl_dcu_bypass_tcon(fsl_dev, fsl_dev->np);
+	fsl_dev->clk = devm_clk_get(&pdev->dev, "dcu");
+	if (IS_ERR(fsl_dev->clk)) {
+		ret = PTR_ERR(fsl_dev->clk);
+		dev_err(&pdev->dev, "could not get clock\n");
+		return ret;
+	}
+	clk_prepare_enable(fsl_dev->clk);
+	dev_set_drvdata(dev->dev, fsl_dev);
+
+	ret = fsl_dcu_drm_modeset_init(fsl_dev);
+	if (ret < 0) {
+		dev_err(&pdev->dev, "failed to initialize mode setting\n");
+		return ret;
+	}
+
+	ret = drm_vblank_init(dev, dev->mode_config.num_crtc);
+	if (ret < 0) {
+		dev_err(&pdev->dev, "failed to initialize vblank\n");
+		goto done;
+	}
+
+	ret = fsl_dcu_drm_irq_init(dev);
+	if (ret < 0)
+		goto done;
+
+	fsl_dcu_fbdev_init(dev);
+
+	return 0;
+done:
+	if (ret)
+		fsl_dcu_unload(dev);
+
+	return ret;
+}
+
+static void fsl_dcu_drm_preclose(struct drm_device *dev, struct drm_file *file)
+{
+	;
+}
+
+static irqreturn_t fsl_dcu_drm_irq(int irq, void *arg)
+{
+	struct drm_device *dev = arg;
+	struct fsl_dcu_drm_device *fsl_dev = dev->dev_private;
+	unsigned int int_status;
+
+	regmap_read(fsl_dev->regmap, DCU_INT_STATUS, &int_status);
+	if (int_status & DCU_INT_STATUS_VBLANK)
+		drm_handle_vblank(dev, 0);
+
+	regmap_write(fsl_dev->regmap, DCU_INT_STATUS, 0xffffffff);
+	regmap_write(fsl_dev->regmap, DCU_UPDATE_MODE, DCU_UPDATE_MODE_READREG);
+
+	return IRQ_HANDLED;
+}
+
+static int fsl_dcu_drm_enable_vblank(struct drm_device *dev, int crtc)
+{
+	return 0;
+}
+
+static void fsl_dcu_drm_disable_vblank(struct drm_device *dev, int crtc)
+{
+	;
+}
+
+static const struct file_operations fsl_dcu_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		= no_llseek,
+	.mmap		= drm_gem_cma_mmap,
+};
+
+static struct drm_driver fsl_dcu_drm_driver = {
+	.driver_features	= DRIVER_HAVE_IRQ | DRIVER_GEM | DRIVER_MODESET
+				| DRIVER_PRIME,
+	.load			= fsl_dcu_load,
+	.unload			= fsl_dcu_unload,
+	.preclose		= fsl_dcu_drm_preclose,
+	.irq_handler		= fsl_dcu_drm_irq,
+	.get_vblank_counter	= drm_vblank_count,
+	.enable_vblank		= fsl_dcu_drm_enable_vblank,
+	.disable_vblank		= fsl_dcu_drm_disable_vblank,
+	.gem_free_object	= drm_gem_cma_free_object,
+	.gem_vm_ops		= &drm_gem_cma_vm_ops,
+	.prime_handle_to_fd	= drm_gem_prime_handle_to_fd,
+	.prime_fd_to_handle	= drm_gem_prime_fd_to_handle,
+	.gem_prime_import	= drm_gem_prime_import,
+	.gem_prime_export	= drm_gem_prime_export,
+	.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,
+	.dumb_create		= drm_gem_cma_dumb_create,
+	.dumb_map_offset	= drm_gem_cma_dumb_map_offset,
+	.dumb_destroy		= drm_gem_dumb_destroy,
+	.fops			= &fsl_dcu_drm_fops,
+	.name			= "fsl-dcu-drm",
+	.desc			= "Freescale DCU DRM",
+	.date			= "20150213",
+	.major			= 1,
+	.minor			= 0,
+};
+
+#ifdef CONFIG_PM_SLEEP
+static int fsl_dcu_drm_pm_suspend(struct device *dev)
+{
+	struct fsl_dcu_drm_device *fsl_dev = dev_get_drvdata(dev);
+
+	if (of_device_is_compatible(fsl_dev->np, "fsl,ls1021a-dcu"))
+		dcu_pixclk_disable();
+
+	drm_kms_helper_poll_disable(fsl_dev->ddev);
+	fsl_dcu_drm_crtc_suspend(&fsl_dev->crtc);
+
+	return 0;
+}
+
+static int fsl_dcu_drm_pm_resume(struct device *dev)
+{
+	struct fsl_dcu_drm_device *fsl_dev = dev_get_drvdata(dev);
+
+	drm_modeset_lock_all(fsl_dev->ddev);
+	fsl_dcu_drm_crtc_resume(&fsl_dev->crtc);
+	drm_modeset_unlock_all(fsl_dev->ddev);
+	drm_kms_helper_poll_enable(fsl_dev->ddev);
+
+	if (of_device_is_compatible(fsl_dev->np, "fsl,ls1021a-dcu"))
+		dcu_pixclk_enable();
+
+	return 0;
+}
+#endif
+
+static const struct dev_pm_ops fsl_dcu_drm_pm_ops = {
+	SET_SYSTEM_SLEEP_PM_OPS(fsl_dcu_drm_pm_suspend, fsl_dcu_drm_pm_resume)
+};
+
+static int fsl_dcu_drm_probe(struct platform_device *pdev)
+{
+	return drm_platform_init(&fsl_dcu_drm_driver, pdev);
+}
+
+static int fsl_dcu_drm_remove(struct platform_device *pdev)
+{
+	struct fsl_dcu_drm_device *fsl_dev = platform_get_drvdata(pdev);
+
+	drm_put_dev(fsl_dev->ddev);
+
+	return 0;
+}
+
+static const struct of_device_id fsl_dcu_of_match[] = {
+		{ .compatible = "fsl,ls1021a-dcu", },
+		{ .compatible = "fsl,vf610-dcu", },
+		{ },
+};
+MODULE_DEVICE_TABLE(of, fsl_dcu_of_match);
+
+static struct platform_driver fsl_dcu_drm_platform_driver = {
+	.probe		= fsl_dcu_drm_probe,
+	.remove		= fsl_dcu_drm_remove,
+	.driver		= {
+		.owner	= THIS_MODULE,
+		.name	= "fsl,dcu",
+		.pm	= &fsl_dcu_drm_pm_ops,
+		.of_match_table = fsl_dcu_of_match,
+	},
+};
+
+module_platform_driver(fsl_dcu_drm_platform_driver);
+
+MODULE_ALIAS("platform:fsl-dcu-drm");
+MODULE_DESCRIPTION("Freescale DCU DRM Driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/gpu/drm/fsl/fsl_dcu_drm_drv.h b/drivers/gpu/drm/fsl/fsl_dcu_drm_drv.h
new file mode 100644
index 0000000..27226109
--- /dev/null
+++ b/drivers/gpu/drm/fsl/fsl_dcu_drm_drv.h
@@ -0,0 +1,210 @@ 
+/*
+ * Copyright 2015 Freescale Semiconductor, Inc.
+ *
+ * Freescale DCU drm device driver
+ *
+ * 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 __FSL_DCU_DRM_DRV_H__
+#define __FSL_DCU_DRM_DRV_H__
+
+#include <linux/kernel.h>
+#include <linux/spinlock.h>
+#include <stddef.h>
+#include <drm/drm.h>
+#include <drm/drmP.h>
+#include <drm/drm_fb_helper.h>
+#include <drm/drm_crtc_helper.h>
+#include <drm/drm_gem_cma_helper.h>
+#include <drm/drm_fb_cma_helper.h>
+
+#include "fsl_dcu_drm_crtc.h"
+#include "fsl_dcu_drm_plane.h"
+#include "fsl_dcu_drm_connector.h"
+#define DRIVER_NAME			"fsl-dcu-drm"
+
+#define DCU_DCU_MODE			0x0010
+#define DCU_MODE_BLEND_ITER(x)		((x) << 20)
+#define DCU_MODE_RASTER_EN		BIT(14)
+#define DCU_MODE_DCU_MODE(x)		(x)
+#define DCU_MODE_DCU_MODE_MASK		0x03
+#define DCU_MODE_OFF			0
+#define DCU_MODE_NORMAL			1
+#define DCU_MODE_TEST			2
+#define DCU_MODE_COLORBAR		3
+
+#define DCU_BGND			0x0014
+#define DCU_BGND_R(x)			((x) << 16)
+#define DCU_BGND_G(x)			((x) << 8)
+#define DCU_BGND_B(x)			(x)
+
+#define DCU_DISP_SIZE			0x0018
+#define DCU_DISP_SIZE_DELTA_Y(x)	((x) << 16)
+/*Regisiter value 1/16 of horizontal resolution*/
+#define DCU_DISP_SIZE_DELTA_X(x)	((x) >> 4)
+
+#define DCU_HSYN_PARA			0x001c
+#define DCU_HSYN_PARA_BP(x)		((x) << 22)
+#define DCU_HSYN_PARA_PW(x)		((x) << 11)
+#define DCU_HSYN_PARA_FP(x)		(x)
+
+#define DCU_VSYN_PARA			0x0020
+#define DCU_VSYN_PARA_BP(x)		((x) << 22)
+#define DCU_VSYN_PARA_PW(x)		((x) << 11)
+#define DCU_VSYN_PARA_FP(x)		(x)
+
+#define DCU_SYN_POL			0x0024
+#define DCU_SYN_POL_INV_PXCK_FALL	(0 << 6)
+#define DCU_SYN_POL_NEG_REMAIN		(0 << 5)
+#define DCU_SYN_POL_INV_VS_LOW		BIT(1)
+#define DCU_SYN_POL_INV_HS_LOW		BIT(0)
+
+#define DCU_THRESHOLD			0x0028
+#define DCU_THRESHOLD_LS_BF_VS(x)	((x) << 16)
+#define DCU_THRESHOLD_OUT_BUF_HIGH(x)	((x) << 8)
+#define DCU_THRESHOLD_OUT_BUF_LOW(x)	(x)
+#define BF_VS_VAL			0x03
+#define BUF_MAX_VAL			0x78
+#define BUF_MIN_VAL			0x0a
+
+#define DCU_INT_STATUS			0x002C
+#define DCU_INT_STATUS_VSYNC		BIT(0)
+#define DCU_INT_STATUS_UNDRUN		BIT(1)
+#define DCU_INT_STATUS_LSBFVS		BIT(2)
+#define DCU_INT_STATUS_VBLANK		BIT(3)
+#define DCU_INT_STATUS_CRCREADY		BIT(4)
+#define DCU_INT_STATUS_CRCOVERFLOW	BIT(5)
+#define DCU_INT_STATUS_P1FIFOLO		BIT(6)
+#define DCU_INT_STATUS_P1FIFOHI		BIT(7)
+#define DCU_INT_STATUS_P2FIFOLO		BIT(8)
+#define DCU_INT_STATUS_P2FIFOHI		BIT(9)
+#define DCU_INT_STATUS_PROGEND		BIT(10)
+#define DCU_INT_STATUS_IPMERROR		BIT(11)
+#define DCU_INT_STATUS_LYRTRANS		BIT(12)
+#define DCU_INT_STATUS_DMATRANS		BIT(14)
+#define DCU_INT_STATUS_P3FIFOLO		BIT(16)
+#define DCU_INT_STATUS_P3FIFOHI		BIT(17)
+#define DCU_INT_STATUS_P4FIFOLO		BIT(18)
+#define DCU_INT_STATUS_P4FIFOHI		BIT(19)
+#define DCU_INT_STATUS_P1EMPTY		BIT(26)
+#define DCU_INT_STATUS_P2EMPTY		BIT(27)
+#define DCU_INT_STATUS_P3EMPTY		BIT(28)
+#define DCU_INT_STATUS_P4EMPTY		BIT(29)
+
+#define DCU_INT_MASK			0x0030
+#define DCU_INT_MASK_VSYNC		BIT(0)
+#define DCU_INT_MASK_UNDRUN		BIT(1)
+#define DCU_INT_MASK_LSBFVS		BIT(2)
+#define DCU_INT_MASK_VBLANK		BIT(3)
+#define DCU_INT_MASK_CRCREADY		BIT(4)
+#define DCU_INT_MASK_CRCOVERFLOW	BIT(5)
+#define DCU_INT_MASK_P1FIFOLO		BIT(6)
+#define DCU_INT_MASK_P1FIFOHI		BIT(7)
+#define DCU_INT_MASK_P2FIFOLO		BIT(8)
+#define DCU_INT_MASK_P2FIFOHI		BIT(9)
+#define DCU_INT_MASK_PROGEND		BIT(10)
+#define DCU_INT_MASK_IPMERROR		BIT(11)
+#define DCU_INT_MASK_LYRTRANS		BIT(12)
+#define DCU_INT_MASK_DMATRANS		BIT(14)
+#define DCU_INT_MASK_P3FIFOLO		BIT(16)
+#define DCU_INT_MASK_P3FIFOHI		BIT(17)
+#define DCU_INT_MASK_P4FIFOLO		BIT(18)
+#define DCU_INT_MASK_P4FIFOHI		BIT(19)
+#define DCU_INT_MASK_P1EMPTY		BIT(26)
+#define DCU_INT_MASK_P2EMPTY		BIT(27)
+#define DCU_INT_MASK_P3EMPTY		BIT(28)
+#define DCU_INT_MASK_P4EMPTY		BIT(29)
+
+#define DCU_DIV_RATIO			0x0054
+
+#define DCU_UPDATE_MODE			0x00cc
+#define DCU_UPDATE_MODE_MODE		BIT(31)
+#define DCU_UPDATE_MODE_READREG		BIT(30)
+
+#define DCU_DCFB_MAX			0x300
+
+#define DCU_CTRLDESCLN_1(x)		(0x200 + (x) * 0x40)
+#define DCU_CTRLDESCLN_1_HEIGHT(x)	((x) << 16)
+#define DCU_CTRLDESCLN_1_WIDTH(x)	(x)
+
+#define DCU_CTRLDESCLN_2(x)		(0x204 + (x) * 0x40)
+#define DCU_CTRLDESCLN_2_POSY(x)	((x) << 16)
+#define DCU_CTRLDESCLN_2_POSX(x)	(x)
+
+#define DCU_CTRLDESCLN_3(x)		(0x208 + (x) * 0x40)
+
+#define DCU_CTRLDESCLN_4(x)		(0x20c + (x) * 0x40)
+#define DCU_CTRLDESCLN_4_EN		BIT(31)
+#define DCU_CTRLDESCLN_4_TILE_EN	BIT(30)
+#define DCU_CTRLDESCLN_4_DATA_SEL_CLUT	BIT(29)
+#define DCU_CTRLDESCLN_4_SAFETY_EN	BIT(28)
+#define DCU_CTRLDESCLN_4_TRANS(x)	((x) << 20)
+#define DCU_CTRLDESCLN_4_BPP(x)		((x) << 16)
+#define DCU_CTRLDESCLN_4_RLE_EN		BIT(15)
+#define DCU_CTRLDESCLN_4_LUOFFS(x)	((x) << 4)
+#define DCU_CTRLDESCLN_4_BB_ON		BIT(2)
+#define DCU_CTRLDESCLN_4_AB(x)		(x)
+
+#define DCU_CTRLDESCLN_5(x)		(0x210 + (x) * 0x40)
+#define DCU_CTRLDESCLN_5_CKMAX_R(x)	((x) << 16)
+#define DCU_CTRLDESCLN_5_CKMAX_G(x)	((x) << 8)
+#define DCU_CTRLDESCLN_5_CKMAX_B(x)	(x)
+
+#define DCU_CTRLDESCLN_6(x)		(0x214 + (x) * 0x40)
+#define DCU_CTRLDESCLN_6_CKMIN_R(x)	((x) << 16)
+#define DCU_CTRLDESCLN_6_CKMIN_G(x)	((x) << 8)
+#define DCU_CTRLDESCLN_6_CKMIN_B(x)	(x)
+
+#define DCU_CTRLDESCLN_7(x)		(0x218 + (x) * 0x40)
+#define DCU_CTRLDESCLN_7_TILE_VER(x)	((x) << 16)
+#define DCU_CTRLDESCLN_7_TILE_HOR(x)	(x)
+
+#define DCU_CTRLDESCLN_8(x)		(0x21c + (x) * 0x40)
+#define DCU_CTRLDESCLN_8_FG_FCOLOR(x)	(x)
+
+#define DCU_CTRLDESCLN_9(x)		(0x220 + (x) * 0x40)
+#define DCU_CTRLDESCLN_9_BG_BCOLOR(x)	(x)
+
+#define DCU_CTRLDESCLN_10(x)		(0x224 + (x) * 0x40)
+#define DCU_CTRLDESCLN_10_POST_SKIP(x)	((x) << 16)
+#define DCU_CTRLDESCLN_10_PRE_SKIP(x)	(x)
+
+#define FSL_DCU_RGB565			4
+#define FSL_DCU_RGB888			5
+#define FSL_DCU_ARGB8888		6
+#define FSL_DCU_ARGB1555		11
+#define FSL_DCU_ARGB4444		12
+#define FSL_DCU_YUV422			14
+
+#define TCON_CTRL1			0x0000
+#define TCON_BYPASS_ENABLE		BIT(29)
+
+#define DBG(fmt, ...) DRM_DEBUG(fmt"\n", ##__VA_ARGS__)
+
+struct clk;
+struct device;
+struct drm_device;
+
+struct fsl_dcu_drm_device {
+	struct device *dev;
+	struct device_node *np;
+	struct regmap *regmap;
+	struct regmap *tcon_regmap;
+	unsigned int irq;
+	struct clk *clk;
+	/*protects hardware register*/
+	spinlock_t irq_lock;
+	struct drm_device *ddev;
+	struct drm_fbdev_cma *fbdev;
+	struct fsl_dcu_drm_crtc crtc;
+	struct drm_encoder encoder;
+	struct fsl_dcu_drm_connector connector;
+};
+
+void fsl_dcu_fbdev_init(struct drm_device *dev);
+
+#endif /* __FSL_DCU_DRM_DRV_H__ */
diff --git a/drivers/gpu/drm/fsl/fsl_dcu_drm_fbdev.c b/drivers/gpu/drm/fsl/fsl_dcu_drm_fbdev.c
new file mode 100644
index 0000000..f8ef0e1
--- /dev/null
+++ b/drivers/gpu/drm/fsl/fsl_dcu_drm_fbdev.c
@@ -0,0 +1,26 @@ 
+/*
+ * Copyright 2015 Freescale Semiconductor, Inc.
+ *
+ * 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.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ */
+
+#include <drm/drmP.h>
+#include <drm/drm_fb_cma_helper.h>
+
+#include "fsl_dcu_drm_drv.h"
+
+/* initialize fbdev helper */
+void fsl_dcu_fbdev_init(struct drm_device *dev)
+{
+	struct fsl_dcu_drm_device *fsl_dev = dev_get_drvdata(dev->dev);
+
+	fsl_dev->fbdev = drm_fbdev_cma_init(dev, 24, 1, 1);
+}
diff --git a/drivers/gpu/drm/fsl/fsl_dcu_drm_kms.c b/drivers/gpu/drm/fsl/fsl_dcu_drm_kms.c
new file mode 100644
index 0000000..0de21c6
--- /dev/null
+++ b/drivers/gpu/drm/fsl/fsl_dcu_drm_kms.c
@@ -0,0 +1,42 @@ 
+/*
+ * Copyright 2015 Freescale Semiconductor, Inc.
+ *
+ * Freescale DCU drm device driver
+ *
+ * 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 "fsl_dcu_drm_crtc.h"
+#include "fsl_dcu_drm_connector.h"
+#include "fsl_dcu_drm_drv.h"
+
+static const struct drm_mode_config_funcs fsl_dcu_drm_mode_config_funcs = {
+	.fb_create = drm_fb_cma_create,
+	.atomic_check = drm_atomic_helper_check,
+	.atomic_commit = drm_atomic_helper_commit,
+};
+
+int fsl_dcu_drm_modeset_init(struct fsl_dcu_drm_device *fsl_dev)
+{
+	drm_mode_config_init(fsl_dev->ddev);
+
+	fsl_dev->ddev->mode_config.min_width = 0;
+	fsl_dev->ddev->mode_config.min_height = 0;
+	fsl_dev->ddev->mode_config.max_width = 2031;
+	fsl_dev->ddev->mode_config.max_height = 2047;
+	fsl_dev->ddev->mode_config.funcs = &fsl_dcu_drm_mode_config_funcs;
+
+	drm_kms_helper_poll_init(fsl_dev->ddev);
+	fsl_dcu_drm_crtc_create(fsl_dev);
+	fsl_dcu_drm_encoder_create(fsl_dev, &fsl_dev->crtc);
+	fsl_dcu_drm_connector_create(fsl_dev, &fsl_dev->encoder);
+	drm_mode_config_reset(fsl_dev->ddev);
+
+	return 0;
+}
diff --git a/drivers/gpu/drm/fsl/fsl_dcu_drm_kms.h b/drivers/gpu/drm/fsl/fsl_dcu_drm_kms.h
new file mode 100644
index 0000000..b9bd299
--- /dev/null
+++ b/drivers/gpu/drm/fsl/fsl_dcu_drm_kms.h
@@ -0,0 +1,17 @@ 
+/*
+ * Copyright 2015 Freescale Semiconductor, Inc.
+ *
+ * Freescale DCU drm device driver
+ *
+ * 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 __FSL_DCU_DRM_KMS_H__
+#define __FSL_DCU_DRM_KMS_H__
+
+int fsl_dcu_drm_modeset_init(struct fsl_dcu_drm_device *fsl_dev);
+
+#endif /* __FSL_DCU_DRM_KMS_H__ */
diff --git a/drivers/gpu/drm/fsl/fsl_dcu_drm_plane.c b/drivers/gpu/drm/fsl/fsl_dcu_drm_plane.c
new file mode 100644
index 0000000..6146e80
--- /dev/null
+++ b/drivers/gpu/drm/fsl/fsl_dcu_drm_plane.c
@@ -0,0 +1,192 @@ 
+/*
+ * Copyright 2015 Freescale Semiconductor, Inc.
+ *
+ * Freescale DCU drm device driver
+ *
+ * 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_crtc.h>
+#include <drm/drm_crtc_helper.h>
+#include <drm/drm_fb_cma_helper.h>
+#include <drm/drm_gem_cma_helper.h>
+#include <linux/regmap.h>
+#include <drm/drm_plane_helper.h>
+#include <drm/drm_atomic_helper.h>
+
+#include "fsl_dcu_drm_drv.h"
+#include "fsl_dcu_drm_kms.h"
+#include "fsl_dcu_drm_plane.h"
+
+#define to_fsl_dcu_plane(plane) \
+	container_of(plane, struct fsl_dcu_drm_plane, plane)
+
+static int
+fsl_dcu_drm_plane_prepare_fb(struct drm_plane *plane,
+			     struct drm_framebuffer *fb,
+			     const struct drm_plane_state *new_state)
+{
+	return 0;
+}
+
+static void
+fsl_dcu_drm_plane_cleanup_fb(struct drm_plane *plane,
+			     struct drm_framebuffer *fb,
+			     const struct drm_plane_state *new_state)
+{
+}
+
+static int fsl_dcu_drm_plane_atomic_check(struct drm_plane *plane,
+					  struct drm_plane_state *state)
+{
+	return 0;
+}
+
+static void fsl_dcu_drm_plane_atomic_disable(struct drm_plane *plane,
+					     struct drm_plane_state *old_state)
+{
+}
+
+void fsl_dcu_drm_plane_atomic_update(struct drm_plane *plane,
+				     struct drm_plane_state *old_state)
+{
+	struct fsl_dcu_drm_device *fsl_dev = plane->dev->dev_private;
+	struct drm_plane_state *state = plane->state;
+	struct drm_framebuffer *fb = plane->state->fb;
+	u32 index, alpha, bpp;
+	struct drm_gem_cma_object *gem;
+	struct fsl_dcu_drm_plane *fsl_plane = to_fsl_dcu_plane(plane);
+
+	index = fsl_plane->index;
+	gem = drm_fb_cma_get_gem_obj(fb, 0);
+
+	switch (fb->pixel_format) {
+	case DRM_FORMAT_RGB565:
+		bpp = FSL_DCU_RGB565;
+		alpha = 0xff;
+		break;
+	case DRM_FORMAT_RGB888:
+		bpp = FSL_DCU_RGB888;
+		alpha = 0xff;
+		break;
+	case DRM_FORMAT_ARGB8888:
+		bpp = FSL_DCU_ARGB8888;
+		alpha = 0xff;
+		break;
+	case DRM_FORMAT_BGRA4444:
+		bpp = FSL_DCU_ARGB4444;
+		alpha = 0xff;
+		break;
+	case DRM_FORMAT_ARGB1555:
+		bpp = FSL_DCU_ARGB1555;
+		alpha = 0xff;
+		break;
+	case DRM_FORMAT_YUV422:
+		bpp = FSL_DCU_YUV422;
+		alpha = 0xff;
+		break;
+	default:
+		return;
+	}
+
+	regmap_write(fsl_dev->regmap, DCU_CTRLDESCLN_1(index),
+		     DCU_CTRLDESCLN_1_HEIGHT(state->crtc_h) |
+		     DCU_CTRLDESCLN_1_WIDTH(state->crtc_w));
+	regmap_write(fsl_dev->regmap, DCU_CTRLDESCLN_2(index),
+		     DCU_CTRLDESCLN_2_POSY(state->crtc_y) |
+		     DCU_CTRLDESCLN_2_POSX(state->crtc_x));
+	regmap_write(fsl_dev->regmap, DCU_CTRLDESCLN_3(index), gem->paddr);
+	regmap_write(fsl_dev->regmap, DCU_CTRLDESCLN_4(index),
+		     DCU_CTRLDESCLN_4_EN |
+		     DCU_CTRLDESCLN_4_TRANS(alpha) |
+		     DCU_CTRLDESCLN_4_BPP(bpp) |
+		     DCU_CTRLDESCLN_4_AB(0));
+	regmap_write(fsl_dev->regmap, DCU_CTRLDESCLN_5(index),
+		     DCU_CTRLDESCLN_5_CKMAX_R(0xFF) |
+		     DCU_CTRLDESCLN_5_CKMAX_G(0xFF) |
+		     DCU_CTRLDESCLN_5_CKMAX_B(0xFF));
+	regmap_write(fsl_dev->regmap, DCU_CTRLDESCLN_6(index),
+		     DCU_CTRLDESCLN_6_CKMIN_R(0) |
+		     DCU_CTRLDESCLN_6_CKMIN_G(0) |
+		     DCU_CTRLDESCLN_6_CKMIN_B(0));
+	regmap_write(fsl_dev->regmap, DCU_CTRLDESCLN_7(index), 0);
+	regmap_write(fsl_dev->regmap, DCU_CTRLDESCLN_8(index),
+		     DCU_CTRLDESCLN_8_FG_FCOLOR(0));
+	regmap_write(fsl_dev->regmap, DCU_CTRLDESCLN_9(index),
+		     DCU_CTRLDESCLN_9_BG_BCOLOR(0));
+	if (of_device_is_compatible(fsl_dev->np, "fsl,ls1021a-dcu"))
+		regmap_write(fsl_dev->regmap, DCU_CTRLDESCLN_10(index),
+			     DCU_CTRLDESCLN_10_POST_SKIP(0) |
+			     DCU_CTRLDESCLN_10_PRE_SKIP(0));
+	regmap_update_bits(fsl_dev->regmap, DCU_DCU_MODE,
+			   DCU_MODE_DCU_MODE_MASK,
+			   DCU_MODE_DCU_MODE(DCU_MODE_NORMAL));
+	regmap_write(fsl_dev->regmap, DCU_UPDATE_MODE, DCU_UPDATE_MODE_READREG);
+}
+
+int fsl_dcu_drm_plane_disable(struct drm_plane *plane)
+{
+	return 0;
+}
+
+void fsl_dcu_drm_plane_destroy(struct drm_plane *plane)
+{
+	fsl_dcu_drm_plane_disable(plane);
+	drm_plane_cleanup(plane);
+}
+
+static const uint32_t fsl_dcu_drm_plane_formats[] = {
+	DRM_FORMAT_RGB565,
+	DRM_FORMAT_RGB888,
+	DRM_FORMAT_ARGB8888,
+	DRM_FORMAT_ARGB4444,
+	DRM_FORMAT_ARGB1555,
+	DRM_FORMAT_YUV422,
+};
+
+static const struct drm_plane_funcs fsl_dcu_drm_plane_funcs = {
+	.update_plane = drm_atomic_helper_update_plane,
+	.disable_plane = drm_atomic_helper_disable_plane,
+	.destroy = fsl_dcu_drm_plane_destroy,
+	.atomic_duplicate_state = drm_atomic_helper_plane_duplicate_state,
+	.atomic_destroy_state = drm_atomic_helper_plane_destroy_state,
+	.reset = drm_atomic_helper_plane_reset,
+};
+
+static const struct drm_plane_helper_funcs fsl_dcu_drm_plane_helper_funcs = {
+	.prepare_fb = fsl_dcu_drm_plane_prepare_fb,
+	.cleanup_fb = fsl_dcu_drm_plane_cleanup_fb,
+	.atomic_check = fsl_dcu_drm_plane_atomic_check,
+	.atomic_update = fsl_dcu_drm_plane_atomic_update,
+	.atomic_disable = fsl_dcu_drm_plane_atomic_disable,
+};
+
+struct drm_plane *fsl_dcu_drm_primary_create_plane(struct drm_device *dev)
+{
+	struct drm_plane *primary;
+	int ret;
+
+	primary = kzalloc(sizeof(*primary), GFP_KERNEL);
+	if (!primary) {
+		DRM_DEBUG_KMS("Failed to allocate primary plane\n");
+		return NULL;
+	}
+
+	/* possible_crtc's will be filled in later by crtc_init */
+	ret = drm_universal_plane_init(dev, primary, 0,
+				       &fsl_dcu_drm_plane_funcs,
+				       fsl_dcu_drm_plane_formats,
+				       ARRAY_SIZE(fsl_dcu_drm_plane_formats),
+				       DRM_PLANE_TYPE_PRIMARY);
+	if (ret) {
+		kfree(primary);
+		primary = NULL;
+	}
+	drm_plane_helper_add(primary, &fsl_dcu_drm_plane_helper_funcs);
+
+	return primary;
+}
diff --git a/drivers/gpu/drm/fsl/fsl_dcu_drm_plane.h b/drivers/gpu/drm/fsl/fsl_dcu_drm_plane.h
new file mode 100644
index 0000000..ccbfa61
--- /dev/null
+++ b/drivers/gpu/drm/fsl/fsl_dcu_drm_plane.h
@@ -0,0 +1,23 @@ 
+/*
+ * Copyright 2015 Freescale Semiconductor, Inc.
+ *
+ * Freescale DCU drm device driver
+ *
+ * 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 __FSL_DCU_DRM_PLANE_H__
+#define __FSL_DCU_DRM_PLANE_H__
+
+struct fsl_dcu_drm_device;
+struct fsl_dcu_drm_plane {
+	struct drm_plane plane;
+	unsigned int index;
+};
+
+struct drm_plane *fsl_dcu_drm_primary_create_plane(struct drm_device *dev);
+
+#endif /* __FSL_DCU_DRM_PLANE_H__ */