]> git.karo-electronics.de Git - karo-tx-linux.git/commitdiff
Merge tag 'sunxi-drm-for-4.12' of https://git.kernel.org/pub/scm/linux/kernel/git...
authorDave Airlie <airlied@redhat.com>
Thu, 20 Apr 2017 03:19:34 +0000 (13:19 +1000)
committerDave Airlie <airlied@redhat.com>
Thu, 20 Apr 2017 03:19:34 +0000 (13:19 +1000)
Allwinner DRM changes for 4.12

Not any functional changes, but a lot of preliminary rework in order to
support multiple display pipelines.

* tag 'sunxi-drm-for-4.12' of https://git.kernel.org/pub/scm/linux/kernel/git/mripard/linux: (26 commits)
  MAINTAINERS: Add sun4i-drm git repo
  drm/sun4i: Pass pointer for underlying backend into layer init
  drm/sun4i: Pass pointers for associated backend and tcon into crtc init
  drm/sun4i: tv: Get tcon and backend pointers from associated crtc
  drm/sun4i: Use embedded tcon pointer to get the tcon's output port node
  drm/sun4i: Fix tcon channel 0 comment about backporch = backporch + hsync
  drm/sun4i: Fix TCON clock and regmap initialization sequence
  drm/sun4i: Grab reserved memory region
  drm/sun4i: Add backend and tcon pointers to sun4i_crtc
  drm/sun4i: Add backend pointer to sun4i_layer
  drm/sun4i: rgb: Pass tcon pointer when initializing RGB encoder
  drm/sun4i: tv: Switch to drm_of_find_possible_crtcs
  drm/sun4i: Drop hardcoded .possible_crtcs values from layers
  drm/sun4i: Drop primary layer pointer from sun4i_drv
  drm/sun4i: Initialize crtc from tcon bind function
  drm/sun4i: Move layers from sun4i_drv to sun4i_crtc
  drm/sun4i: Add end of list element for sun4i_layers_init's returned list
  drm/sun4i: Set drm_crtc.port to the underlying TCON's output port node
  drm/sun4i: Make sunxi_rgb2yuv_coef constant
  drm/sun4i: Make sun4i_crtc_init return ERR_PTR style error codes
  ...

15 files changed:
MAINTAINERS
drivers/gpu/drm/sun4i/Makefile
drivers/gpu/drm/sun4i/sun4i_backend.c
drivers/gpu/drm/sun4i/sun4i_crtc.c
drivers/gpu/drm/sun4i/sun4i_crtc.h
drivers/gpu/drm/sun4i/sun4i_drv.c
drivers/gpu/drm/sun4i/sun4i_drv.h
drivers/gpu/drm/sun4i/sun4i_framebuffer.c
drivers/gpu/drm/sun4i/sun4i_layer.c
drivers/gpu/drm/sun4i/sun4i_layer.h
drivers/gpu/drm/sun4i/sun4i_rgb.c
drivers/gpu/drm/sun4i/sun4i_rgb.h
drivers/gpu/drm/sun4i/sun4i_tcon.c
drivers/gpu/drm/sun4i/sun4i_tcon.h
drivers/gpu/drm/sun4i/sun4i_tv.c

index 93ed0319b3d6f636e6dc5c46e3dc9bf5f42f4034..afba0760fdaf1e27dd3af3d625e2e99790cdccfb 100644 (file)
@@ -4247,6 +4247,7 @@ L:        dri-devel@lists.freedesktop.org
 S:     Supported
 F:     drivers/gpu/drm/sun4i/
 F:     Documentation/devicetree/bindings/display/sunxi/sun4i-drm.txt
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/mripard/linux.git
 
 DRM DRIVERS FOR AMLOGIC SOCS
 M:     Neil Armstrong <narmstrong@baylibre.com>
index d625a82a6e5fb8e570764e26aa2e202f5f65bc0d..59b757350a1f5516d5a9558c7cbfddf3a7192741 100644 (file)
@@ -1,11 +1,11 @@
-sun4i-drm-y += sun4i_crtc.o
 sun4i-drm-y += sun4i_drv.o
 sun4i-drm-y += sun4i_framebuffer.o
-sun4i-drm-y += sun4i_layer.o
 
 sun4i-tcon-y += sun4i_tcon.o
 sun4i-tcon-y += sun4i_rgb.o
 sun4i-tcon-y += sun4i_dotclock.o
+sun4i-tcon-y += sun4i_crtc.o
+sun4i-tcon-y += sun4i_layer.o
 
 obj-$(CONFIG_DRM_SUN4I)                += sun4i-drm.o sun4i-tcon.o
 obj-$(CONFIG_DRM_SUN4I)                += sun4i_backend.o
index 08ce15070f80f0c6b11a2bf1648711a647f695f0..d660741ba475af98c22d36275f950661c6b98a9e 100644 (file)
@@ -24,7 +24,7 @@
 #include "sun4i_backend.h"
 #include "sun4i_drv.h"
 
-static u32 sunxi_rgb2yuv_coef[12] = {
+static const u32 sunxi_rgb2yuv_coef[12] = {
        0x00000107, 0x00000204, 0x00000064, 0x00000108,
        0x00003f69, 0x00003ed6, 0x000001c1, 0x00000808,
        0x000001c1, 0x00003e88, 0x00003fb8, 0x00000808
index a5d546a68e1651edb9e19bcdfd66da0f42cb6de8..3c876c3a356a635aeef947e99f3d9f89aad6cbea 100644 (file)
@@ -19,6 +19,7 @@
 #include <linux/clk-provider.h>
 #include <linux/ioport.h>
 #include <linux/of_address.h>
+#include <linux/of_graph.h>
 #include <linux/of_irq.h>
 #include <linux/regmap.h>
 
@@ -27,6 +28,7 @@
 #include "sun4i_backend.h"
 #include "sun4i_crtc.h"
 #include "sun4i_drv.h"
+#include "sun4i_layer.h"
 #include "sun4i_tcon.h"
 
 static void sun4i_crtc_atomic_begin(struct drm_crtc *crtc,
@@ -50,12 +52,11 @@ static void sun4i_crtc_atomic_flush(struct drm_crtc *crtc,
                                    struct drm_crtc_state *old_state)
 {
        struct sun4i_crtc *scrtc = drm_crtc_to_sun4i_crtc(crtc);
-       struct sun4i_drv *drv = scrtc->drv;
        struct drm_pending_vblank_event *event = crtc->state->event;
 
        DRM_DEBUG_DRIVER("Committing plane changes\n");
 
-       sun4i_backend_commit(drv->backend);
+       sun4i_backend_commit(scrtc->backend);
 
        if (event) {
                crtc->state->event = NULL;
@@ -72,11 +73,10 @@ static void sun4i_crtc_atomic_flush(struct drm_crtc *crtc,
 static void sun4i_crtc_disable(struct drm_crtc *crtc)
 {
        struct sun4i_crtc *scrtc = drm_crtc_to_sun4i_crtc(crtc);
-       struct sun4i_drv *drv = scrtc->drv;
 
        DRM_DEBUG_DRIVER("Disabling the CRTC\n");
 
-       sun4i_tcon_disable(drv->tcon);
+       sun4i_tcon_disable(scrtc->tcon);
 
        if (crtc->state->event && !crtc->state->active) {
                spin_lock_irq(&crtc->dev->event_lock);
@@ -90,11 +90,10 @@ static void sun4i_crtc_disable(struct drm_crtc *crtc)
 static void sun4i_crtc_enable(struct drm_crtc *crtc)
 {
        struct sun4i_crtc *scrtc = drm_crtc_to_sun4i_crtc(crtc);
-       struct sun4i_drv *drv = scrtc->drv;
 
        DRM_DEBUG_DRIVER("Enabling the CRTC\n");
 
-       sun4i_tcon_enable(drv->tcon);
+       sun4i_tcon_enable(scrtc->tcon);
 }
 
 static const struct drm_crtc_helper_funcs sun4i_crtc_helper_funcs = {
@@ -107,11 +106,10 @@ static const struct drm_crtc_helper_funcs sun4i_crtc_helper_funcs = {
 static int sun4i_crtc_enable_vblank(struct drm_crtc *crtc)
 {
        struct sun4i_crtc *scrtc = drm_crtc_to_sun4i_crtc(crtc);
-       struct sun4i_drv *drv = scrtc->drv;
 
        DRM_DEBUG_DRIVER("Enabling VBLANK on crtc %p\n", crtc);
 
-       sun4i_tcon_enable_vblank(drv->tcon, true);
+       sun4i_tcon_enable_vblank(scrtc->tcon, true);
 
        return 0;
 }
@@ -119,11 +117,10 @@ static int sun4i_crtc_enable_vblank(struct drm_crtc *crtc)
 static void sun4i_crtc_disable_vblank(struct drm_crtc *crtc)
 {
        struct sun4i_crtc *scrtc = drm_crtc_to_sun4i_crtc(crtc);
-       struct sun4i_drv *drv = scrtc->drv;
 
        DRM_DEBUG_DRIVER("Disabling VBLANK on crtc %p\n", crtc);
 
-       sun4i_tcon_enable_vblank(drv->tcon, false);
+       sun4i_tcon_enable_vblank(scrtc->tcon, false);
 }
 
 static const struct drm_crtc_funcs sun4i_crtc_funcs = {
@@ -137,28 +134,67 @@ static const struct drm_crtc_funcs sun4i_crtc_funcs = {
        .disable_vblank         = sun4i_crtc_disable_vblank,
 };
 
-struct sun4i_crtc *sun4i_crtc_init(struct drm_device *drm)
+struct sun4i_crtc *sun4i_crtc_init(struct drm_device *drm,
+                                  struct sun4i_backend *backend,
+                                  struct sun4i_tcon *tcon)
 {
-       struct sun4i_drv *drv = drm->dev_private;
        struct sun4i_crtc *scrtc;
-       int ret;
+       struct drm_plane *primary = NULL, *cursor = NULL;
+       int ret, i;
 
        scrtc = devm_kzalloc(drm->dev, sizeof(*scrtc), GFP_KERNEL);
        if (!scrtc)
+               return ERR_PTR(-ENOMEM);
+       scrtc->backend = backend;
+       scrtc->tcon = tcon;
+
+       /* Create our layers */
+       scrtc->layers = sun4i_layers_init(drm, scrtc->backend);
+       if (IS_ERR(scrtc->layers)) {
+               dev_err(drm->dev, "Couldn't create the planes\n");
                return NULL;
-       scrtc->drv = drv;
+       }
+
+       /* find primary and cursor planes for drm_crtc_init_with_planes */
+       for (i = 0; scrtc->layers[i]; i++) {
+               struct sun4i_layer *layer = scrtc->layers[i];
+
+               switch (layer->plane.type) {
+               case DRM_PLANE_TYPE_PRIMARY:
+                       primary = &layer->plane;
+                       break;
+               case DRM_PLANE_TYPE_CURSOR:
+                       cursor = &layer->plane;
+                       break;
+               default:
+                       break;
+               }
+       }
 
        ret = drm_crtc_init_with_planes(drm, &scrtc->crtc,
-                                       drv->primary,
-                                       NULL,
+                                       primary,
+                                       cursor,
                                        &sun4i_crtc_funcs,
                                        NULL);
        if (ret) {
                dev_err(drm->dev, "Couldn't init DRM CRTC\n");
-               return NULL;
+               return ERR_PTR(ret);
        }
 
        drm_crtc_helper_add(&scrtc->crtc, &sun4i_crtc_helper_funcs);
 
+       /* Set crtc.port to output port node of the tcon */
+       scrtc->crtc.port = of_graph_get_port_by_id(scrtc->tcon->dev->of_node,
+                                                  1);
+
+       /* Set possible_crtcs to this crtc for overlay planes */
+       for (i = 0; scrtc->layers[i]; i++) {
+               uint32_t possible_crtcs = BIT(drm_crtc_index(&scrtc->crtc));
+               struct sun4i_layer *layer = scrtc->layers[i];
+
+               if (layer->plane.type == DRM_PLANE_TYPE_OVERLAY)
+                       layer->plane.possible_crtcs = possible_crtcs;
+       }
+
        return scrtc;
 }
index dec8ce4d9b25b79c7c3de4272a924d5464031e1f..230cb8f0d60166087e33dce3893bec541baf5954 100644 (file)
@@ -17,7 +17,9 @@ struct sun4i_crtc {
        struct drm_crtc                 crtc;
        struct drm_pending_vblank_event *event;
 
-       struct sun4i_drv                *drv;
+       struct sun4i_backend            *backend;
+       struct sun4i_tcon               *tcon;
+       struct sun4i_layer              **layers;
 };
 
 static inline struct sun4i_crtc *drm_crtc_to_sun4i_crtc(struct drm_crtc *crtc)
@@ -25,6 +27,8 @@ static inline struct sun4i_crtc *drm_crtc_to_sun4i_crtc(struct drm_crtc *crtc)
        return container_of(crtc, struct sun4i_crtc, crtc);
 }
 
-struct sun4i_crtc *sun4i_crtc_init(struct drm_device *drm);
+struct sun4i_crtc *sun4i_crtc_init(struct drm_device *drm,
+                                  struct sun4i_backend *backend,
+                                  struct sun4i_tcon *tcon);
 
 #endif /* _SUN4I_CRTC_H_ */
index 329ea56106a5c1e546d4dbd9b0f654884f0b3b6d..8ddd72cd58736e3f6e0935087cccdab802e6dd96 100644 (file)
@@ -12,6 +12,7 @@
 
 #include <linux/component.h>
 #include <linux/of_graph.h>
+#include <linux/of_reserved_mem.h>
 
 #include <drm/drmP.h>
 #include <drm/drm_crtc_helper.h>
 #include <drm/drm_fb_helper.h>
 #include <drm/drm_of.h>
 
-#include "sun4i_crtc.h"
 #include "sun4i_drv.h"
 #include "sun4i_framebuffer.h"
-#include "sun4i_layer.h"
+#include "sun4i_tcon.h"
 
 DEFINE_DRM_GEM_CMA_FOPS(sun4i_drv_fops);
 
@@ -92,30 +92,25 @@ static int sun4i_drv_bind(struct device *dev)
        }
        drm->dev_private = drv;
 
-       drm_vblank_init(drm, 1);
+       ret = of_reserved_mem_device_init(dev);
+       if (ret && ret != -ENODEV) {
+               dev_err(drm->dev, "Couldn't claim our memory region\n");
+               goto free_drm;
+       }
+
+       /* drm_vblank_init calls kcalloc, which can fail */
+       ret = drm_vblank_init(drm, 1);
+       if (ret)
+               goto free_mem_region;
+
        drm_mode_config_init(drm);
 
        ret = component_bind_all(drm->dev, drm);
        if (ret) {
                dev_err(drm->dev, "Couldn't bind all pipelines components\n");
-               goto free_drm;
-       }
-
-       /* Create our layers */
-       drv->layers = sun4i_layers_init(drm);
-       if (IS_ERR(drv->layers)) {
-               dev_err(drm->dev, "Couldn't create the planes\n");
-               ret = PTR_ERR(drv->layers);
-               goto free_drm;
+               goto cleanup_mode_config;
        }
 
-       /* Create our CRTC */
-       drv->crtc = sun4i_crtc_init(drm);
-       if (!drv->crtc) {
-               dev_err(drm->dev, "Couldn't create the CRTC\n");
-               ret = -EINVAL;
-               goto free_drm;
-       }
        drm->irq_enabled = true;
 
        /* Remove early framebuffers (ie. simplefb) */
@@ -126,7 +121,7 @@ static int sun4i_drv_bind(struct device *dev)
        if (IS_ERR(drv->fbdev)) {
                dev_err(drm->dev, "Couldn't create our framebuffer\n");
                ret = PTR_ERR(drv->fbdev);
-               goto free_drm;
+               goto cleanup_mode_config;
        }
 
        /* Enable connectors polling */
@@ -134,10 +129,18 @@ static int sun4i_drv_bind(struct device *dev)
 
        ret = drm_dev_register(drm, 0);
        if (ret)
-               goto free_drm;
+               goto finish_poll;
 
        return 0;
 
+finish_poll:
+       drm_kms_helper_poll_fini(drm);
+       sun4i_framebuffer_free(drm);
+cleanup_mode_config:
+       drm_mode_config_cleanup(drm);
+       drm_vblank_cleanup(drm);
+free_mem_region:
+       of_reserved_mem_device_release(dev);
 free_drm:
        drm_dev_unref(drm);
        return ret;
@@ -150,7 +153,9 @@ static void sun4i_drv_unbind(struct device *dev)
        drm_dev_unregister(drm);
        drm_kms_helper_poll_fini(drm);
        sun4i_framebuffer_free(drm);
+       drm_mode_config_cleanup(drm);
        drm_vblank_cleanup(drm);
+       of_reserved_mem_device_release(dev);
        drm_dev_unref(drm);
 }
 
index 597353eab728f240566d206433b367ffe194e9f1..5df50126ff52531be776e79db00f629347efae25 100644 (file)
 
 struct sun4i_drv {
        struct sun4i_backend    *backend;
-       struct sun4i_crtc       *crtc;
        struct sun4i_tcon       *tcon;
 
-       struct drm_plane        *primary;
        struct drm_fbdev_cma    *fbdev;
-
-       struct sun4i_layer      **layers;
 };
 
 #endif /* _SUN4I_DRV_H_ */
index 2c3beff8b53e2d89de3a6d4e705ae3b9b047ae2f..9872e0fc03b0ec44db0d3ac01c5106ec5d9d426f 100644 (file)
@@ -48,5 +48,4 @@ void sun4i_framebuffer_free(struct drm_device *drm)
        struct sun4i_drv *drv = drm->dev_private;
 
        drm_fbdev_cma_fini(drv->fbdev);
-       drm_mode_config_cleanup(drm);
 }
index 5d53c977bca5d0cce752e389f7dc9b38ce195155..f26bde5b9117cabaa6d0cf08af9471cee80f45e8 100644 (file)
@@ -16,7 +16,6 @@
 #include <drm/drmP.h>
 
 #include "sun4i_backend.h"
-#include "sun4i_drv.h"
 #include "sun4i_layer.h"
 
 struct sun4i_plane_desc {
@@ -36,8 +35,7 @@ static void sun4i_backend_layer_atomic_disable(struct drm_plane *plane,
                                               struct drm_plane_state *old_state)
 {
        struct sun4i_layer *layer = plane_to_sun4i_layer(plane);
-       struct sun4i_drv *drv = layer->drv;
-       struct sun4i_backend *backend = drv->backend;
+       struct sun4i_backend *backend = layer->backend;
 
        sun4i_backend_layer_enable(backend, layer->id, false);
 }
@@ -46,8 +44,7 @@ static void sun4i_backend_layer_atomic_update(struct drm_plane *plane,
                                              struct drm_plane_state *old_state)
 {
        struct sun4i_layer *layer = plane_to_sun4i_layer(plane);
-       struct sun4i_drv *drv = layer->drv;
-       struct sun4i_backend *backend = drv->backend;
+       struct sun4i_backend *backend = layer->backend;
 
        sun4i_backend_update_layer_coord(backend, layer->id, plane);
        sun4i_backend_update_layer_formats(backend, layer->id, plane);
@@ -104,9 +101,9 @@ static const struct sun4i_plane_desc sun4i_backend_planes[] = {
 };
 
 static struct sun4i_layer *sun4i_layer_init_one(struct drm_device *drm,
+                                               struct sun4i_backend *backend,
                                                const struct sun4i_plane_desc *plane)
 {
-       struct sun4i_drv *drv = drm->dev_private;
        struct sun4i_layer *layer;
        int ret;
 
@@ -114,7 +111,8 @@ static struct sun4i_layer *sun4i_layer_init_one(struct drm_device *drm,
        if (!layer)
                return ERR_PTR(-ENOMEM);
 
-       ret = drm_universal_plane_init(drm, &layer->plane, BIT(0),
+       /* possible crtcs are set later */
+       ret = drm_universal_plane_init(drm, &layer->plane, 0,
                                       &sun4i_backend_layer_funcs,
                                       plane->formats, plane->nformats,
                                       plane->type, NULL);
@@ -125,22 +123,19 @@ static struct sun4i_layer *sun4i_layer_init_one(struct drm_device *drm,
 
        drm_plane_helper_add(&layer->plane,
                             &sun4i_backend_layer_helper_funcs);
-       layer->drv = drv;
-
-       if (plane->type == DRM_PLANE_TYPE_PRIMARY)
-               drv->primary = &layer->plane;
+       layer->backend = backend;
 
        return layer;
 }
 
-struct sun4i_layer **sun4i_layers_init(struct drm_device *drm)
+struct sun4i_layer **sun4i_layers_init(struct drm_device *drm,
+                                      struct sun4i_backend *backend)
 {
-       struct sun4i_drv *drv = drm->dev_private;
        struct sun4i_layer **layers;
        int i;
 
-       layers = devm_kcalloc(drm->dev, ARRAY_SIZE(sun4i_backend_planes),
-                             sizeof(**layers), GFP_KERNEL);
+       layers = devm_kcalloc(drm->dev, ARRAY_SIZE(sun4i_backend_planes) + 1,
+                             sizeof(*layers), GFP_KERNEL);
        if (!layers)
                return ERR_PTR(-ENOMEM);
 
@@ -167,9 +162,9 @@ struct sun4i_layer **sun4i_layers_init(struct drm_device *drm)
         */
        for (i = 0; i < ARRAY_SIZE(sun4i_backend_planes); i++) {
                const struct sun4i_plane_desc *plane = &sun4i_backend_planes[i];
-               struct sun4i_layer *layer = layers[i];
+               struct sun4i_layer *layer;
 
-               layer = sun4i_layer_init_one(drm, plane);
+               layer = sun4i_layer_init_one(drm, backend, plane);
                if (IS_ERR(layer)) {
                        dev_err(drm->dev, "Couldn't initialize %s plane\n",
                                i ? "overlay" : "primary");
@@ -178,11 +173,12 @@ struct sun4i_layer **sun4i_layers_init(struct drm_device *drm)
 
                DRM_DEBUG_DRIVER("Assigning %s plane to pipe %d\n",
                                 i ? "overlay" : "primary", plane->pipe);
-               regmap_update_bits(drv->backend->regs, SUN4I_BACKEND_ATTCTL_REG0(i),
+               regmap_update_bits(backend->regs, SUN4I_BACKEND_ATTCTL_REG0(i),
                                   SUN4I_BACKEND_ATTCTL_REG0_LAY_PIPESEL_MASK,
                                   SUN4I_BACKEND_ATTCTL_REG0_LAY_PIPESEL(plane->pipe));
 
                layer->id = i;
+               layers[i] = layer;
        };
 
        return layers;
index a2f65d7a3f4e930dd5020dd8297f6780406ab9be..4be1f0919df22cd5b6478f2f2f24ef1324ba3048 100644 (file)
@@ -16,6 +16,7 @@
 struct sun4i_layer {
        struct drm_plane        plane;
        struct sun4i_drv        *drv;
+       struct sun4i_backend    *backend;
        int                     id;
 };
 
@@ -25,6 +26,7 @@ plane_to_sun4i_layer(struct drm_plane *plane)
        return container_of(plane, struct sun4i_layer, plane);
 }
 
-struct sun4i_layer **sun4i_layers_init(struct drm_device *drm);
+struct sun4i_layer **sun4i_layers_init(struct drm_device *drm,
+                                      struct sun4i_backend *backend);
 
 #endif /* _SUN4I_LAYER_H_ */
index 46280dd70c9e05800aed87a6de4e512066da46e9..67f0b91a99de057933583d8aa786f23c73cb1af8 100644 (file)
@@ -18,7 +18,7 @@
 #include <drm/drm_of.h>
 #include <drm/drm_panel.h>
 
-#include "sun4i_drv.h"
+#include "sun4i_crtc.h"
 #include "sun4i_tcon.h"
 #include "sun4i_rgb.h"
 
@@ -26,7 +26,7 @@ struct sun4i_rgb {
        struct drm_connector    connector;
        struct drm_encoder      encoder;
 
-       struct sun4i_drv        *drv;
+       struct sun4i_tcon       *tcon;
 };
 
 static inline struct sun4i_rgb *
@@ -47,8 +47,7 @@ static int sun4i_rgb_get_modes(struct drm_connector *connector)
 {
        struct sun4i_rgb *rgb =
                drm_connector_to_sun4i_rgb(connector);
-       struct sun4i_drv *drv = rgb->drv;
-       struct sun4i_tcon *tcon = drv->tcon;
+       struct sun4i_tcon *tcon = rgb->tcon;
 
        return drm_panel_get_modes(tcon->panel);
 }
@@ -57,8 +56,7 @@ static int sun4i_rgb_mode_valid(struct drm_connector *connector,
                                struct drm_display_mode *mode)
 {
        struct sun4i_rgb *rgb = drm_connector_to_sun4i_rgb(connector);
-       struct sun4i_drv *drv = rgb->drv;
-       struct sun4i_tcon *tcon = drv->tcon;
+       struct sun4i_tcon *tcon = rgb->tcon;
        u32 hsync = mode->hsync_end - mode->hsync_start;
        u32 vsync = mode->vsync_end - mode->vsync_start;
        unsigned long rate = mode->clock * 1000;
@@ -115,8 +113,7 @@ static void
 sun4i_rgb_connector_destroy(struct drm_connector *connector)
 {
        struct sun4i_rgb *rgb = drm_connector_to_sun4i_rgb(connector);
-       struct sun4i_drv *drv = rgb->drv;
-       struct sun4i_tcon *tcon = drv->tcon;
+       struct sun4i_tcon *tcon = rgb->tcon;
 
        drm_panel_detach(tcon->panel);
        drm_connector_cleanup(connector);
@@ -141,8 +138,7 @@ static int sun4i_rgb_atomic_check(struct drm_encoder *encoder,
 static void sun4i_rgb_encoder_enable(struct drm_encoder *encoder)
 {
        struct sun4i_rgb *rgb = drm_encoder_to_sun4i_rgb(encoder);
-       struct sun4i_drv *drv = rgb->drv;
-       struct sun4i_tcon *tcon = drv->tcon;
+       struct sun4i_tcon *tcon = rgb->tcon;
 
        DRM_DEBUG_DRIVER("Enabling RGB output\n");
 
@@ -158,8 +154,7 @@ static void sun4i_rgb_encoder_enable(struct drm_encoder *encoder)
 static void sun4i_rgb_encoder_disable(struct drm_encoder *encoder)
 {
        struct sun4i_rgb *rgb = drm_encoder_to_sun4i_rgb(encoder);
-       struct sun4i_drv *drv = rgb->drv;
-       struct sun4i_tcon *tcon = drv->tcon;
+       struct sun4i_tcon *tcon = rgb->tcon;
 
        DRM_DEBUG_DRIVER("Disabling RGB output\n");
 
@@ -177,8 +172,7 @@ static void sun4i_rgb_encoder_mode_set(struct drm_encoder *encoder,
                                       struct drm_display_mode *adjusted_mode)
 {
        struct sun4i_rgb *rgb = drm_encoder_to_sun4i_rgb(encoder);
-       struct sun4i_drv *drv = rgb->drv;
-       struct sun4i_tcon *tcon = drv->tcon;
+       struct sun4i_tcon *tcon = rgb->tcon;
 
        sun4i_tcon0_mode_set(tcon, mode);
 
@@ -204,10 +198,8 @@ static struct drm_encoder_funcs sun4i_rgb_enc_funcs = {
        .destroy        = sun4i_rgb_enc_destroy,
 };
 
-int sun4i_rgb_init(struct drm_device *drm)
+int sun4i_rgb_init(struct drm_device *drm, struct sun4i_tcon *tcon)
 {
-       struct sun4i_drv *drv = drm->dev_private;
-       struct sun4i_tcon *tcon = drv->tcon;
        struct drm_encoder *encoder;
        struct drm_bridge *bridge;
        struct sun4i_rgb *rgb;
@@ -216,7 +208,7 @@ int sun4i_rgb_init(struct drm_device *drm)
        rgb = devm_kzalloc(drm->dev, sizeof(*rgb), GFP_KERNEL);
        if (!rgb)
                return -ENOMEM;
-       rgb->drv = drv;
+       rgb->tcon = tcon;
        encoder = &rgb->encoder;
 
        ret = drm_of_find_panel_or_bridge(tcon->dev->of_node, 1, 0,
@@ -239,7 +231,7 @@ int sun4i_rgb_init(struct drm_device *drm)
        }
 
        /* The RGB encoder can only work with the TCON channel 0 */
-       rgb->encoder.possible_crtcs = BIT(0);
+       rgb->encoder.possible_crtcs = BIT(drm_crtc_index(&tcon->crtc->crtc));
 
        if (tcon->panel) {
                drm_connector_helper_add(&rgb->connector,
index 7c4da4c8acdd452f8d24ad4ba0e863001ebf3e44..40c18f4a6c7e960af334ae897d76c9819fc8b934 100644 (file)
@@ -13,6 +13,6 @@
 #ifndef _SUN4I_RGB_H_
 #define _SUN4I_RGB_H_
 
-int sun4i_rgb_init(struct drm_device *drm);
+int sun4i_rgb_init(struct drm_device *drm, struct sun4i_tcon *tcon);
 
 #endif /* _SUN4I_RGB_H_ */
index 2e4e365cecf9f506823fae7fe3bcb4c94863b3ea..9a83a85529ac46ab0b351e7111cded6ef7313259 100644 (file)
@@ -142,7 +142,7 @@ void sun4i_tcon0_mode_set(struct sun4i_tcon *tcon,
 
        /*
         * This is called a backporch in the register documentation,
-        * but it really is the front porch + hsync
+        * but it really is the back porch + hsync
         */
        bp = mode->crtc_htotal - mode->crtc_hsync_start;
        DRM_DEBUG_DRIVER("Setting horizontal total %d, backporch %d\n",
@@ -155,7 +155,7 @@ void sun4i_tcon0_mode_set(struct sun4i_tcon *tcon,
 
        /*
         * This is called a backporch in the register documentation,
-        * but it really is the front porch + hsync
+        * but it really is the back porch + hsync
         */
        bp = mode->crtc_vtotal - mode->crtc_vsync_start;
        DRM_DEBUG_DRIVER("Setting vertical total %d, backporch %d\n",
@@ -289,8 +289,7 @@ static irqreturn_t sun4i_tcon_handler(int irq, void *private)
 {
        struct sun4i_tcon *tcon = private;
        struct drm_device *drm = tcon->drm;
-       struct sun4i_drv *drv = drm->dev_private;
-       struct sun4i_crtc *scrtc = drv->crtc;
+       struct sun4i_crtc *scrtc = tcon->crtc;
        unsigned int status;
 
        regmap_read(tcon->regs, SUN4I_TCON_GINT0_REG, &status);
@@ -335,12 +334,11 @@ static int sun4i_tcon_init_clocks(struct device *dev,
                }
        }
 
-       return sun4i_dclk_create(dev, tcon);
+       return 0;
 }
 
 static void sun4i_tcon_free_clocks(struct sun4i_tcon *tcon)
 {
-       sun4i_dclk_free(tcon);
        clk_disable_unprepare(tcon->clk);
 }
 
@@ -437,30 +435,45 @@ static int sun4i_tcon_bind(struct device *dev, struct device *master,
                return ret;
        }
 
+       ret = sun4i_tcon_init_clocks(dev, tcon);
+       if (ret) {
+               dev_err(dev, "Couldn't init our TCON clocks\n");
+               goto err_assert_reset;
+       }
+
        ret = sun4i_tcon_init_regmap(dev, tcon);
        if (ret) {
                dev_err(dev, "Couldn't init our TCON regmap\n");
-               goto err_assert_reset;
+               goto err_free_clocks;
        }
 
-       ret = sun4i_tcon_init_clocks(dev, tcon);
+       ret = sun4i_dclk_create(dev, tcon);
        if (ret) {
-               dev_err(dev, "Couldn't init our TCON clocks\n");
-               goto err_assert_reset;
+               dev_err(dev, "Couldn't create our TCON dot clock\n");
+               goto err_free_clocks;
        }
 
        ret = sun4i_tcon_init_irq(dev, tcon);
        if (ret) {
                dev_err(dev, "Couldn't init our TCON interrupts\n");
+               goto err_free_dotclock;
+       }
+
+       tcon->crtc = sun4i_crtc_init(drm, drv->backend, tcon);
+       if (IS_ERR(tcon->crtc)) {
+               dev_err(dev, "Couldn't create our CRTC\n");
+               ret = PTR_ERR(tcon->crtc);
                goto err_free_clocks;
        }
 
-       ret = sun4i_rgb_init(drm);
+       ret = sun4i_rgb_init(drm, tcon);
        if (ret < 0)
                goto err_free_clocks;
 
        return 0;
 
+err_free_dotclock:
+       sun4i_dclk_free(tcon);
 err_free_clocks:
        sun4i_tcon_free_clocks(tcon);
 err_assert_reset:
@@ -473,6 +486,7 @@ static void sun4i_tcon_unbind(struct device *dev, struct device *master,
 {
        struct sun4i_tcon *tcon = dev_get_drvdata(dev);
 
+       sun4i_dclk_free(tcon);
        sun4i_tcon_free_clocks(tcon);
 }
 
index 166064bafe2eb3b914ed52ea1cbf200501885846..f636343a935dce6889d9f0651354191b9af03c6d 100644 (file)
@@ -169,6 +169,9 @@ struct sun4i_tcon {
 
        /* Platform adjustments */
        const struct sun4i_tcon_quirks  *quirks;
+
+       /* Associated crtc */
+       struct sun4i_crtc               *crtc;
 };
 
 struct drm_bridge *sun4i_tcon_find_bridge(struct device_node *node);
index c6f47222e8fc733fb73e0a944b545cb0f7e266a8..49c49431a053e34a3ebb9cb34a7490adda1c2860 100644 (file)
 #include <drm/drmP.h>
 #include <drm/drm_atomic_helper.h>
 #include <drm/drm_crtc_helper.h>
+#include <drm/drm_of.h>
 #include <drm/drm_panel.h>
 
 #include "sun4i_backend.h"
+#include "sun4i_crtc.h"
 #include "sun4i_drv.h"
 #include "sun4i_tcon.h"
 
@@ -349,8 +351,9 @@ static int sun4i_tv_atomic_check(struct drm_encoder *encoder,
 static void sun4i_tv_disable(struct drm_encoder *encoder)
 {
        struct sun4i_tv *tv = drm_encoder_to_sun4i_tv(encoder);
-       struct sun4i_drv *drv = tv->drv;
-       struct sun4i_tcon *tcon = drv->tcon;
+       struct sun4i_crtc *crtc = drm_crtc_to_sun4i_crtc(encoder->crtc);
+       struct sun4i_tcon *tcon = crtc->tcon;
+       struct sun4i_backend *backend = crtc->backend;
 
        DRM_DEBUG_DRIVER("Disabling the TV Output\n");
 
@@ -359,18 +362,19 @@ static void sun4i_tv_disable(struct drm_encoder *encoder)
        regmap_update_bits(tv->regs, SUN4I_TVE_EN_REG,
                           SUN4I_TVE_EN_ENABLE,
                           0);
-       sun4i_backend_disable_color_correction(drv->backend);
+       sun4i_backend_disable_color_correction(backend);
 }
 
 static void sun4i_tv_enable(struct drm_encoder *encoder)
 {
        struct sun4i_tv *tv = drm_encoder_to_sun4i_tv(encoder);
-       struct sun4i_drv *drv = tv->drv;
-       struct sun4i_tcon *tcon = drv->tcon;
+       struct sun4i_crtc *crtc = drm_crtc_to_sun4i_crtc(encoder->crtc);
+       struct sun4i_tcon *tcon = crtc->tcon;
+       struct sun4i_backend *backend = crtc->backend;
 
        DRM_DEBUG_DRIVER("Enabling the TV Output\n");
 
-       sun4i_backend_apply_color_correction(drv->backend);
+       sun4i_backend_apply_color_correction(backend);
 
        regmap_update_bits(tv->regs, SUN4I_TVE_EN_REG,
                           SUN4I_TVE_EN_ENABLE,
@@ -384,8 +388,8 @@ static void sun4i_tv_mode_set(struct drm_encoder *encoder,
                              struct drm_display_mode *adjusted_mode)
 {
        struct sun4i_tv *tv = drm_encoder_to_sun4i_tv(encoder);
-       struct sun4i_drv *drv = tv->drv;
-       struct sun4i_tcon *tcon = drv->tcon;
+       struct sun4i_crtc *crtc = drm_crtc_to_sun4i_crtc(encoder->crtc);
+       struct sun4i_tcon *tcon = crtc->tcon;
        const struct tv_mode *tv_mode = sun4i_tv_find_tv_by_mode(mode);
 
        sun4i_tcon1_mode_set(tcon, mode);
@@ -623,7 +627,12 @@ static int sun4i_tv_bind(struct device *dev, struct device *master,
                goto err_disable_clk;
        }
 
-       tv->encoder.possible_crtcs = BIT(0);
+       tv->encoder.possible_crtcs = drm_of_find_possible_crtcs(drm,
+                                                               dev->of_node);
+       if (!tv->encoder.possible_crtcs) {
+               ret = -EPROBE_DEFER;
+               goto err_disable_clk;
+       }
 
        drm_connector_helper_add(&tv->connector,
                                 &sun4i_tv_comp_connector_helper_funcs);