diff options
author | Dave Airlie <airlied@redhat.com> | 2017-04-20 05:19:34 +0200 |
---|---|---|
committer | Dave Airlie <airlied@redhat.com> | 2017-04-20 05:19:34 +0200 |
commit | cb2e77c1d53366696a7f47dbcedba99603ca1b55 (patch) | |
tree | 70d3d3e649b312f715d0239ac8c75ea1637664fd | |
parent | Merge tag 'v4.11-rc7' into drm-next (diff) | |
parent | MAINTAINERS: Add sun4i-drm git repo (diff) | |
download | linux-cb2e77c1d53366696a7f47dbcedba99603ca1b55.tar.xz linux-cb2e77c1d53366696a7f47dbcedba99603ca1b55.zip |
Merge tag 'sunxi-drm-for-4.12' of https://git.kernel.org/pub/scm/linux/kernel/git/mripard/linux into drm-next
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
...
-rw-r--r-- | MAINTAINERS | 1 | ||||
-rw-r--r-- | drivers/gpu/drm/sun4i/Makefile | 4 | ||||
-rw-r--r-- | drivers/gpu/drm/sun4i/sun4i_backend.c | 2 | ||||
-rw-r--r-- | drivers/gpu/drm/sun4i/sun4i_crtc.c | 70 | ||||
-rw-r--r-- | drivers/gpu/drm/sun4i/sun4i_crtc.h | 8 | ||||
-rw-r--r-- | drivers/gpu/drm/sun4i/sun4i_drv.c | 47 | ||||
-rw-r--r-- | drivers/gpu/drm/sun4i/sun4i_drv.h | 4 | ||||
-rw-r--r-- | drivers/gpu/drm/sun4i/sun4i_framebuffer.c | 1 | ||||
-rw-r--r-- | drivers/gpu/drm/sun4i/sun4i_layer.c | 32 | ||||
-rw-r--r-- | drivers/gpu/drm/sun4i/sun4i_layer.h | 4 | ||||
-rw-r--r-- | drivers/gpu/drm/sun4i/sun4i_rgb.c | 30 | ||||
-rw-r--r-- | drivers/gpu/drm/sun4i/sun4i_rgb.h | 2 | ||||
-rw-r--r-- | drivers/gpu/drm/sun4i/sun4i_tcon.c | 36 | ||||
-rw-r--r-- | drivers/gpu/drm/sun4i/sun4i_tcon.h | 3 | ||||
-rw-r--r-- | drivers/gpu/drm/sun4i/sun4i_tv.c | 27 |
15 files changed, 164 insertions, 107 deletions
diff --git a/MAINTAINERS b/MAINTAINERS index 93ed0319b3d6..afba0760fdaf 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -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> diff --git a/drivers/gpu/drm/sun4i/Makefile b/drivers/gpu/drm/sun4i/Makefile index d625a82a6e5f..59b757350a1f 100644 --- a/drivers/gpu/drm/sun4i/Makefile +++ b/drivers/gpu/drm/sun4i/Makefile @@ -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 diff --git a/drivers/gpu/drm/sun4i/sun4i_backend.c b/drivers/gpu/drm/sun4i/sun4i_backend.c index 08ce15070f80..d660741ba475 100644 --- a/drivers/gpu/drm/sun4i/sun4i_backend.c +++ b/drivers/gpu/drm/sun4i/sun4i_backend.c @@ -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 diff --git a/drivers/gpu/drm/sun4i/sun4i_crtc.c b/drivers/gpu/drm/sun4i/sun4i_crtc.c index a5d546a68e16..3c876c3a356a 100644 --- a/drivers/gpu/drm/sun4i/sun4i_crtc.c +++ b/drivers/gpu/drm/sun4i/sun4i_crtc.c @@ -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; } diff --git a/drivers/gpu/drm/sun4i/sun4i_crtc.h b/drivers/gpu/drm/sun4i/sun4i_crtc.h index dec8ce4d9b25..230cb8f0d601 100644 --- a/drivers/gpu/drm/sun4i/sun4i_crtc.h +++ b/drivers/gpu/drm/sun4i/sun4i_crtc.h @@ -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_ */ diff --git a/drivers/gpu/drm/sun4i/sun4i_drv.c b/drivers/gpu/drm/sun4i/sun4i_drv.c index 329ea56106a5..8ddd72cd5873 100644 --- a/drivers/gpu/drm/sun4i/sun4i_drv.c +++ b/drivers/gpu/drm/sun4i/sun4i_drv.c @@ -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> @@ -20,10 +21,9 @@ #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); } diff --git a/drivers/gpu/drm/sun4i/sun4i_drv.h b/drivers/gpu/drm/sun4i/sun4i_drv.h index 597353eab728..5df50126ff52 100644 --- a/drivers/gpu/drm/sun4i/sun4i_drv.h +++ b/drivers/gpu/drm/sun4i/sun4i_drv.h @@ -18,13 +18,9 @@ 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_ */ diff --git a/drivers/gpu/drm/sun4i/sun4i_framebuffer.c b/drivers/gpu/drm/sun4i/sun4i_framebuffer.c index 2c3beff8b53e..9872e0fc03b0 100644 --- a/drivers/gpu/drm/sun4i/sun4i_framebuffer.c +++ b/drivers/gpu/drm/sun4i/sun4i_framebuffer.c @@ -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); } diff --git a/drivers/gpu/drm/sun4i/sun4i_layer.c b/drivers/gpu/drm/sun4i/sun4i_layer.c index 5d53c977bca5..f26bde5b9117 100644 --- a/drivers/gpu/drm/sun4i/sun4i_layer.c +++ b/drivers/gpu/drm/sun4i/sun4i_layer.c @@ -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; diff --git a/drivers/gpu/drm/sun4i/sun4i_layer.h b/drivers/gpu/drm/sun4i/sun4i_layer.h index a2f65d7a3f4e..4be1f0919df2 100644 --- a/drivers/gpu/drm/sun4i/sun4i_layer.h +++ b/drivers/gpu/drm/sun4i/sun4i_layer.h @@ -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_ */ diff --git a/drivers/gpu/drm/sun4i/sun4i_rgb.c b/drivers/gpu/drm/sun4i/sun4i_rgb.c index 46280dd70c9e..67f0b91a99de 100644 --- a/drivers/gpu/drm/sun4i/sun4i_rgb.c +++ b/drivers/gpu/drm/sun4i/sun4i_rgb.c @@ -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, diff --git a/drivers/gpu/drm/sun4i/sun4i_rgb.h b/drivers/gpu/drm/sun4i/sun4i_rgb.h index 7c4da4c8acdd..40c18f4a6c7e 100644 --- a/drivers/gpu/drm/sun4i/sun4i_rgb.h +++ b/drivers/gpu/drm/sun4i/sun4i_rgb.h @@ -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_ */ diff --git a/drivers/gpu/drm/sun4i/sun4i_tcon.c b/drivers/gpu/drm/sun4i/sun4i_tcon.c index 2e4e365cecf9..9a83a85529ac 100644 --- a/drivers/gpu/drm/sun4i/sun4i_tcon.c +++ b/drivers/gpu/drm/sun4i/sun4i_tcon.c @@ -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); } diff --git a/drivers/gpu/drm/sun4i/sun4i_tcon.h b/drivers/gpu/drm/sun4i/sun4i_tcon.h index 166064bafe2e..f636343a935d 100644 --- a/drivers/gpu/drm/sun4i/sun4i_tcon.h +++ b/drivers/gpu/drm/sun4i/sun4i_tcon.h @@ -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); diff --git a/drivers/gpu/drm/sun4i/sun4i_tv.c b/drivers/gpu/drm/sun4i/sun4i_tv.c index c6f47222e8fc..49c49431a053 100644 --- a/drivers/gpu/drm/sun4i/sun4i_tv.c +++ b/drivers/gpu/drm/sun4i/sun4i_tv.c @@ -19,9 +19,11 @@ #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); |