RE: [PATCH v5 1/3] drm/layerscape: Add Freescale DCU DRM driver

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Hi Mark,

 

Thank you very much for your review!

 

From: Mark yao [mailto:mark.yao@xxxxxxxxxxxxxx]
Sent: Wednesday, July 01, 2015 9:59 AM
To: Wang Jianwei-B52261
Cc: David Airlie; daniel.vetter@xxxxxxxxx; stefan@xxxxxxxx; dri-devel; linux-kernel; linux-arm-kernel@xxxxxxxxxxxxxxxxxxx; Wang Jianwei-B52261
Subject: Re: [PATCH v5 1/3] drm/layerscape: Add Freescale DCU DRM driver

 
From: Jianwei Wang <b52261@xxxxxxxxxxxxx>
 
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 BGRA4444 ARGB1555 direct colors with an alpha channel and YUV422 format.
(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@xxxxxxxxxxxxx>
Signed-off-by: Xiubo Li <lixiubo@xxxxxxxxxxxxxxxxxxxx>
Signed-off-by: Jianwei Wang <jianwei.wang@xxxxxxxxxxxxx>
---
 
Changed in V5
 
- Update commit message
- Add layer registers initialization
- Remove unused functions
- Rename driver folder
- Move pixel clock control functions to fsl_dcu_drm_drv.c
- remove redundant enable the clock implicitly using regmap
- Add maintainer message
 
Changed in V4:
 
-This version doesn't have functionality changed  Just a minor adjustment.
 
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-dcu/fsl,dcu.txt    |  50 +++
 MAINTAINERS                                        |   8 +
 drivers/gpu/drm/Kconfig                            |   2 +
 drivers/gpu/drm/Makefile                           |   1 +
 drivers/gpu/drm/fsl-dcu/Kconfig                    |  17 +
 drivers/gpu/drm/fsl-dcu/Makefile                   |   7 +
 drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_connector.c    | 194 +++++++++++
 drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_connector.h    |  30 ++
 drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_crtc.c         | 172 ++++++++++
 drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_crtc.h         |  22 ++
 drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_drv.c          | 373 +++++++++++++++++++++
 drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_drv.h          | 223 ++++++++++++
 drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_fbdev.c        |  26 ++
 drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_kms.c          |  42 +++
 drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_kms.h          |  17 +
 drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_plane.c        | 192 +++++++++++
 drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_plane.h        |  23 ++
 17 files changed, 1399 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/drm/fsl-dcu/fsl,dcu.txt
 create mode 100644 drivers/gpu/drm/fsl-dcu/Kconfig  create mode 100644 drivers/gpu/drm/fsl-dcu/Makefile  create mode 100644 drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_connector.c
 create mode 100644 drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_connector.h
 create mode 100644 drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_crtc.c
 create mode 100644 drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_crtc.h
 create mode 100644 drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_drv.c
 create mode 100644 drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_drv.h
 create mode 100644 drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_fbdev.c
 create mode 100644 drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_kms.c
 create mode 100644 drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_kms.h
 create mode 100644 drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_plane.c
 create mode 100644 drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_plane.h
 
diff --git a/Documentation/devicetree/bindings/drm/fsl-dcu/fsl,dcu.txt b/Documentation/devicetree/bindings/drm/fsl-dcu/fsl,dcu.txt
new file mode 100644
index 0000000..bdc7d5b
--- /dev/null
+++ b/Documentation/devicetree/bindings/drm/fsl-dcu/fsl,dcu.txt
@@ -0,0 +1,49 @@
+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/MAINTAINERS b/MAINTAINERS
index 885be14..a6cff2f4 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -3398,6 +3398,14 @@ S:      Maintained
 F:     drivers/gpu/drm/imx/
 F:     Documentation/devicetree/bindings/drm/imx/
 
+DRM DRIVERS FOR FREESCALE DCU
+M:     Jianwei Wang <jianwei.wang@xxxxxxxxxxxxx>
+M:     Alison Wang <alison.wang@xxxxxxxxxxxxx>
+L:     dri-devel@xxxxxxxxxxxxxxxxxxxxx
+S:     Supported
+F:     drivers/gpu/drm/fsl-dcu/
+F:     Documentation/devicetree/bindings/drm/fsl-dcu/
+
 DRM DRIVERS FOR NVIDIA TEGRA
 M:     Thierry Reding <thierry.reding@xxxxxxxxx>
 M:     Terje Bergström <tbergstrom@xxxxxxxxxx>
diff --git a/drivers/gpu/drm/Kconfig b/drivers/gpu/drm/Kconfig index 151a050..e64cf18 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-dcu/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..398eccf 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-dcu/
 obj-$(CONFIG_DRM_RCAR_DU) += rcar-du/
 obj-$(CONFIG_DRM_SHMOBILE) +=shmobile/
 obj-$(CONFIG_DRM_OMAP) += omapdrm/
diff --git a/drivers/gpu/drm/fsl-dcu/Kconfig b/drivers/gpu/drm/fsl-dcu/Kconfig new file mode 100644 index 0000000..e4f8df0
--- /dev/null
+++ b/drivers/gpu/drm/fsl-dcu/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-dcu/Makefile b/drivers/gpu/drm/fsl-dcu/Makefile
new file mode 100644
index 0000000..336b4a6
--- /dev/null
+++ b/drivers/gpu/drm/fsl-dcu/Makefile
@@ -0,0 +1,7 @@
+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-dcu/fsl_dcu_drm_connector.c b/drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_connector.c
new file mode 100644
index 0000000..799682d
--- /dev/null
+++ b/drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_connector.c
@@ -0,0 +1,194 @@
+/*
+ * 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 drm_crtc *crtc)
+{
+       struct drm_encoder *encoder = &fsl_dev->encoder;
+       int ret;
+
+       encoder->possible_crtcs = 1;
+       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;
+
+       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;
+               }

Use panel-simple driver instead the display node timing I think is better.
See Documentation/devicetree/bindings/panel/simple-panel.txt and
       drivers/gpu/drm/panel/panel-simple.c

Panel info add into panel driver, other people will easy to reuse the panel.

 got it.

 
+             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-dcu/fsl_dcu_drm_connector.h b/drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_connector.h
new file mode 100644
index 0000000..8141a29
--- /dev/null
+++ b/drivers/gpu/drm/fsl-dcu/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 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-dcu/fsl_dcu_drm_crtc.c b/drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_crtc.c
new file mode 100644
index 0000000..4065a7c
--- /dev/null
+++ b/drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_crtc.c
@@ -0,0 +1,172 @@
+/*
+ * 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)
+
+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 void fsl_dcu_drm_crtc_dpms(struct drm_crtc *crtc, int mode) { }
+
+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 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;
+      int i, ret;
+
+      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);
+
+      for (i = 0; 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);
+             if (of_device_is_compatible(fsl_dev->np, "fsl,ls1021a-dcu"))
+                     regmap_write(fsl_dev->regmap, DCU_CTRLDESCLN_10(i), 0);
+      }
+      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-dcu/fsl_dcu_drm_crtc.h b/drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_crtc.h
new file mode 100644
index 0000000..193785f
--- /dev/null
+++ b/drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_crtc.h
@@ -0,0 +1,22 @@
+/*
+ * 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;
+
+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-dcu/fsl_dcu_drm_drv.c b/drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_drv.c
new file mode 100644
index 0000000..1edf7be
--- /dev/null
+++ b/drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_drv.c
@@ -0,0 +1,373 @@
+/*
+ * 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 <linux/mfd/syscon.h>
+
+#include <drm/drmP.h>
+
+#include "fsl_dcu_drm_drv.h"
+#include "fsl_dcu_drm_crtc.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(&pdev->dev,
+                     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 void dcu_pixclk_enable(void)
+{
+      struct regmap *scfg_regmap;
+
+      scfg_regmap = syscon_regmap_lookup_by_compatible("fsl,ls1021a-scfg");
+      if (IS_ERR(scfg_regmap)) {
+             pr_err("No syscfg phandle specified\n");
+             return;
+      }
+
+      regmap_write(scfg_regmap, SCFG_PIXCLKCR, PXCK_ENABLE); }
+
+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;
+      dev_set_drvdata(dev->dev, 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->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);
+      fsl_dev->regmap = devm_regmap_init_mmio(&pdev->dev, 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);
+
+      if (of_device_is_compatible(fsl_dev->np, "fsl,ls1021a-dcu"))
+             dcu_pixclk_enable();
+      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,


Your patch support atomic, I think driver_features need add DRIVER_ATOMIC

Ok!

 
+      .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 void dcu_pixclk_disable(void)
+{
+      struct regmap *scfg_regmap;
+
+      scfg_regmap = syscon_regmap_lookup_by_compatible("fsl,ls1021a-scfg");
+      if (IS_ERR(scfg_regmap)) {
+             pr_err("No syscfg phandle specified\n");
+             return;
+      }
+
+      regmap_write(scfg_regmap, SCFG_PIXCLKCR, PXCK_DISABLE); }
+
+static int fsl_dcu_drm_pm_suspend(struct device *dev) {
+      struct fsl_dcu_drm_device *fsl_dev = dev_get_drvdata(dev);
Andrzej Hajda told me at my drm driver:
  drm_dev can be NULL here, it can happen when system is suspended
  before all components are bound. It can also contain invalid pointer
  if after successfull drm initialization de-initialization happens for
  some reason.
 
  Some workaround is to check for null here and set drvdata to null on
  master unbind. But I guess it should be protected somehow to avoid races
  in accessing drvdata.
 
You didn't use components, but maybe fsl_dev can be NULL for some reason as Andrzej said.
 
-- 
ark
 
Ok, I’ll update these soon.
 
--
BR.
Jianwei
_______________________________________________
dri-devel mailing list
dri-devel@xxxxxxxxxxxxxxxxxxxxx
http://lists.freedesktop.org/mailman/listinfo/dri-devel

[Index of Archives]     [Linux DRI Users]     [Linux Intel Graphics]     [Linux USB Devel]     [Video for Linux]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]     [XFree86]     [Linux USB Devel]     [Video for Linux]     [Linux Audio Users]     [Linux Kernel]     [Linux SCSI]     [XFree86]
  Powered by Linux