Allwinner DRM changes for 4.12

Not any functional changes, but a lot of preliminary rework in order to
 support multiple display pipelines.
 -----BEGIN PGP SIGNATURE-----
 
 iQIcBAABCAAGBQJY5fHyAAoJEBx+YmzsjxAgnQwQAKsMoIzz8cWI6DByFVOo4IrB
 c8sTThSGh08EiLK05E8JVKedUX2w9Gn7GatwaCur0CSjjQr2evzOvhGjjAVdi2fS
 jDw5j8S4GY6XJMzSZyq2Q6cbshZJqNp5ZThqD9/xDbYOWM1YxOFzybIK/f0hDzcG
 k+qPKtTdXDGdlLfrV44ZIOim63jYD+Nv+C4RyrVny+W6Z3bRg6SyiotDNB3E3ToV
 8hM8nvFE8SWxmx/eWRcUbnH1YPVNjEU2Uw6l1OhBaovtHKL/dD61/OBZ/MGwr64o
 HsrWxlwbdQkv1FxR3NUfeRMCfhDKYyQgBuW8P0H1JlHWTov6lijcmq7L5lASw01j
 3FzNpZ1r8/wXncj0nwwXaPtnq81IL2ek4Af4E2p46gFJJ+SU5UMWI4C5KZflidzS
 Wlhg+3xiiAhmfQef2rCdkERJ/BHN9DyVeadGF+FDxJRyqhnY8fOYrTpxYlAikUSg
 hL3Eqy8v111eaORV+k7NBqjkvCMPKe+7yEiH65mAjt/l446FbLi5IEdIdxnR91Nt
 7kdbgpJqx5wZfRqJrfqUxd/td4GTGgWmSKfPcqs1j5azG52SB1T0+T5ztF0S9z1M
 zS41ixquxPBt4l7dMtYerHiYGVYUSyF2CHIgAJs3HI1jR/qs6W7EPk0kBANNPSVu
 +mT1QyeTAYaF9PZxlHvU
 =XlmY
 -----END PGP SIGNATURE-----

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
  ...
This commit is contained in:
Dave Airlie 2017-04-20 13:19:34 +10:00
commit cb2e77c1d5
15 changed files with 168 additions and 111 deletions

View File

@ -4247,6 +4247,7 @@ L: dri-devel@lists.freedesktop.org
S: Supported S: Supported
F: drivers/gpu/drm/sun4i/ F: drivers/gpu/drm/sun4i/
F: Documentation/devicetree/bindings/display/sunxi/sun4i-drm.txt 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 DRM DRIVERS FOR AMLOGIC SOCS
M: Neil Armstrong <narmstrong@baylibre.com> M: Neil Armstrong <narmstrong@baylibre.com>

View File

@ -1,11 +1,11 @@
sun4i-drm-y += sun4i_crtc.o
sun4i-drm-y += sun4i_drv.o sun4i-drm-y += sun4i_drv.o
sun4i-drm-y += sun4i_framebuffer.o sun4i-drm-y += sun4i_framebuffer.o
sun4i-drm-y += sun4i_layer.o
sun4i-tcon-y += sun4i_tcon.o sun4i-tcon-y += sun4i_tcon.o
sun4i-tcon-y += sun4i_rgb.o sun4i-tcon-y += sun4i_rgb.o
sun4i-tcon-y += sun4i_dotclock.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-drm.o sun4i-tcon.o
obj-$(CONFIG_DRM_SUN4I) += sun4i_backend.o obj-$(CONFIG_DRM_SUN4I) += sun4i_backend.o

View File

@ -24,7 +24,7 @@
#include "sun4i_backend.h" #include "sun4i_backend.h"
#include "sun4i_drv.h" #include "sun4i_drv.h"
static u32 sunxi_rgb2yuv_coef[12] = { static const u32 sunxi_rgb2yuv_coef[12] = {
0x00000107, 0x00000204, 0x00000064, 0x00000108, 0x00000107, 0x00000204, 0x00000064, 0x00000108,
0x00003f69, 0x00003ed6, 0x000001c1, 0x00000808, 0x00003f69, 0x00003ed6, 0x000001c1, 0x00000808,
0x000001c1, 0x00003e88, 0x00003fb8, 0x00000808 0x000001c1, 0x00003e88, 0x00003fb8, 0x00000808

View File

@ -19,6 +19,7 @@
#include <linux/clk-provider.h> #include <linux/clk-provider.h>
#include <linux/ioport.h> #include <linux/ioport.h>
#include <linux/of_address.h> #include <linux/of_address.h>
#include <linux/of_graph.h>
#include <linux/of_irq.h> #include <linux/of_irq.h>
#include <linux/regmap.h> #include <linux/regmap.h>
@ -27,6 +28,7 @@
#include "sun4i_backend.h" #include "sun4i_backend.h"
#include "sun4i_crtc.h" #include "sun4i_crtc.h"
#include "sun4i_drv.h" #include "sun4i_drv.h"
#include "sun4i_layer.h"
#include "sun4i_tcon.h" #include "sun4i_tcon.h"
static void sun4i_crtc_atomic_begin(struct drm_crtc *crtc, 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 drm_crtc_state *old_state)
{ {
struct sun4i_crtc *scrtc = drm_crtc_to_sun4i_crtc(crtc); 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; struct drm_pending_vblank_event *event = crtc->state->event;
DRM_DEBUG_DRIVER("Committing plane changes\n"); DRM_DEBUG_DRIVER("Committing plane changes\n");
sun4i_backend_commit(drv->backend); sun4i_backend_commit(scrtc->backend);
if (event) { if (event) {
crtc->state->event = NULL; 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) static void sun4i_crtc_disable(struct drm_crtc *crtc)
{ {
struct sun4i_crtc *scrtc = drm_crtc_to_sun4i_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"); DRM_DEBUG_DRIVER("Disabling the CRTC\n");
sun4i_tcon_disable(drv->tcon); sun4i_tcon_disable(scrtc->tcon);
if (crtc->state->event && !crtc->state->active) { if (crtc->state->event && !crtc->state->active) {
spin_lock_irq(&crtc->dev->event_lock); 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) static void sun4i_crtc_enable(struct drm_crtc *crtc)
{ {
struct sun4i_crtc *scrtc = drm_crtc_to_sun4i_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"); 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 = { 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) static int sun4i_crtc_enable_vblank(struct drm_crtc *crtc)
{ {
struct sun4i_crtc *scrtc = drm_crtc_to_sun4i_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); 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; 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) static void sun4i_crtc_disable_vblank(struct drm_crtc *crtc)
{ {
struct sun4i_crtc *scrtc = drm_crtc_to_sun4i_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); 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 = { 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, .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; 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); scrtc = devm_kzalloc(drm->dev, sizeof(*scrtc), GFP_KERNEL);
if (!scrtc) 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; 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, ret = drm_crtc_init_with_planes(drm, &scrtc->crtc,
drv->primary, primary,
NULL, cursor,
&sun4i_crtc_funcs, &sun4i_crtc_funcs,
NULL); NULL);
if (ret) { if (ret) {
dev_err(drm->dev, "Couldn't init DRM CRTC\n"); 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); 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; return scrtc;
} }

View File

@ -17,7 +17,9 @@ struct sun4i_crtc {
struct drm_crtc crtc; struct drm_crtc crtc;
struct drm_pending_vblank_event *event; 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) 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); 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_ */ #endif /* _SUN4I_CRTC_H_ */

View File

@ -12,6 +12,7 @@
#include <linux/component.h> #include <linux/component.h>
#include <linux/of_graph.h> #include <linux/of_graph.h>
#include <linux/of_reserved_mem.h>
#include <drm/drmP.h> #include <drm/drmP.h>
#include <drm/drm_crtc_helper.h> #include <drm/drm_crtc_helper.h>
@ -20,10 +21,9 @@
#include <drm/drm_fb_helper.h> #include <drm/drm_fb_helper.h>
#include <drm/drm_of.h> #include <drm/drm_of.h>
#include "sun4i_crtc.h"
#include "sun4i_drv.h" #include "sun4i_drv.h"
#include "sun4i_framebuffer.h" #include "sun4i_framebuffer.h"
#include "sun4i_layer.h" #include "sun4i_tcon.h"
DEFINE_DRM_GEM_CMA_FOPS(sun4i_drv_fops); 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->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); drm_mode_config_init(drm);
ret = component_bind_all(drm->dev, drm); ret = component_bind_all(drm->dev, drm);
if (ret) { if (ret) {
dev_err(drm->dev, "Couldn't bind all pipelines components\n"); dev_err(drm->dev, "Couldn't bind all pipelines components\n");
goto free_drm; goto cleanup_mode_config;
} }
/* 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;
}
/* 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; drm->irq_enabled = true;
/* Remove early framebuffers (ie. simplefb) */ /* Remove early framebuffers (ie. simplefb) */
@ -126,7 +121,7 @@ static int sun4i_drv_bind(struct device *dev)
if (IS_ERR(drv->fbdev)) { if (IS_ERR(drv->fbdev)) {
dev_err(drm->dev, "Couldn't create our framebuffer\n"); dev_err(drm->dev, "Couldn't create our framebuffer\n");
ret = PTR_ERR(drv->fbdev); ret = PTR_ERR(drv->fbdev);
goto free_drm; goto cleanup_mode_config;
} }
/* Enable connectors polling */ /* Enable connectors polling */
@ -134,10 +129,18 @@ static int sun4i_drv_bind(struct device *dev)
ret = drm_dev_register(drm, 0); ret = drm_dev_register(drm, 0);
if (ret) if (ret)
goto free_drm; goto finish_poll;
return 0; 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: free_drm:
drm_dev_unref(drm); drm_dev_unref(drm);
return ret; return ret;
@ -150,7 +153,9 @@ static void sun4i_drv_unbind(struct device *dev)
drm_dev_unregister(drm); drm_dev_unregister(drm);
drm_kms_helper_poll_fini(drm); drm_kms_helper_poll_fini(drm);
sun4i_framebuffer_free(drm); sun4i_framebuffer_free(drm);
drm_mode_config_cleanup(drm);
drm_vblank_cleanup(drm); drm_vblank_cleanup(drm);
of_reserved_mem_device_release(dev);
drm_dev_unref(drm); drm_dev_unref(drm);
} }

View File

@ -18,13 +18,9 @@
struct sun4i_drv { struct sun4i_drv {
struct sun4i_backend *backend; struct sun4i_backend *backend;
struct sun4i_crtc *crtc;
struct sun4i_tcon *tcon; struct sun4i_tcon *tcon;
struct drm_plane *primary;
struct drm_fbdev_cma *fbdev; struct drm_fbdev_cma *fbdev;
struct sun4i_layer **layers;
}; };
#endif /* _SUN4I_DRV_H_ */ #endif /* _SUN4I_DRV_H_ */

View File

@ -48,5 +48,4 @@ void sun4i_framebuffer_free(struct drm_device *drm)
struct sun4i_drv *drv = drm->dev_private; struct sun4i_drv *drv = drm->dev_private;
drm_fbdev_cma_fini(drv->fbdev); drm_fbdev_cma_fini(drv->fbdev);
drm_mode_config_cleanup(drm);
} }

View File

@ -16,7 +16,6 @@
#include <drm/drmP.h> #include <drm/drmP.h>
#include "sun4i_backend.h" #include "sun4i_backend.h"
#include "sun4i_drv.h"
#include "sun4i_layer.h" #include "sun4i_layer.h"
struct sun4i_plane_desc { 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 drm_plane_state *old_state)
{ {
struct sun4i_layer *layer = plane_to_sun4i_layer(plane); struct sun4i_layer *layer = plane_to_sun4i_layer(plane);
struct sun4i_drv *drv = layer->drv; struct sun4i_backend *backend = layer->backend;
struct sun4i_backend *backend = drv->backend;
sun4i_backend_layer_enable(backend, layer->id, false); 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 drm_plane_state *old_state)
{ {
struct sun4i_layer *layer = plane_to_sun4i_layer(plane); struct sun4i_layer *layer = plane_to_sun4i_layer(plane);
struct sun4i_drv *drv = layer->drv; struct sun4i_backend *backend = layer->backend;
struct sun4i_backend *backend = drv->backend;
sun4i_backend_update_layer_coord(backend, layer->id, plane); sun4i_backend_update_layer_coord(backend, layer->id, plane);
sun4i_backend_update_layer_formats(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, static struct sun4i_layer *sun4i_layer_init_one(struct drm_device *drm,
struct sun4i_backend *backend,
const struct sun4i_plane_desc *plane) const struct sun4i_plane_desc *plane)
{ {
struct sun4i_drv *drv = drm->dev_private;
struct sun4i_layer *layer; struct sun4i_layer *layer;
int ret; int ret;
@ -114,7 +111,8 @@ static struct sun4i_layer *sun4i_layer_init_one(struct drm_device *drm,
if (!layer) if (!layer)
return ERR_PTR(-ENOMEM); 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, &sun4i_backend_layer_funcs,
plane->formats, plane->nformats, plane->formats, plane->nformats,
plane->type, NULL); 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, drm_plane_helper_add(&layer->plane,
&sun4i_backend_layer_helper_funcs); &sun4i_backend_layer_helper_funcs);
layer->drv = drv; layer->backend = backend;
if (plane->type == DRM_PLANE_TYPE_PRIMARY)
drv->primary = &layer->plane;
return layer; 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; struct sun4i_layer **layers;
int i; int i;
layers = devm_kcalloc(drm->dev, ARRAY_SIZE(sun4i_backend_planes), layers = devm_kcalloc(drm->dev, ARRAY_SIZE(sun4i_backend_planes) + 1,
sizeof(**layers), GFP_KERNEL); sizeof(*layers), GFP_KERNEL);
if (!layers) if (!layers)
return ERR_PTR(-ENOMEM); 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++) { for (i = 0; i < ARRAY_SIZE(sun4i_backend_planes); i++) {
const struct sun4i_plane_desc *plane = &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)) { if (IS_ERR(layer)) {
dev_err(drm->dev, "Couldn't initialize %s plane\n", dev_err(drm->dev, "Couldn't initialize %s plane\n",
i ? "overlay" : "primary"); 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", DRM_DEBUG_DRIVER("Assigning %s plane to pipe %d\n",
i ? "overlay" : "primary", plane->pipe); 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_MASK,
SUN4I_BACKEND_ATTCTL_REG0_LAY_PIPESEL(plane->pipe)); SUN4I_BACKEND_ATTCTL_REG0_LAY_PIPESEL(plane->pipe));
layer->id = i; layer->id = i;
layers[i] = layer;
}; };
return layers; return layers;

View File

@ -16,6 +16,7 @@
struct sun4i_layer { struct sun4i_layer {
struct drm_plane plane; struct drm_plane plane;
struct sun4i_drv *drv; struct sun4i_drv *drv;
struct sun4i_backend *backend;
int id; int id;
}; };
@ -25,6 +26,7 @@ plane_to_sun4i_layer(struct drm_plane *plane)
return container_of(plane, struct sun4i_layer, 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_ */ #endif /* _SUN4I_LAYER_H_ */

View File

@ -18,7 +18,7 @@
#include <drm/drm_of.h> #include <drm/drm_of.h>
#include <drm/drm_panel.h> #include <drm/drm_panel.h>
#include "sun4i_drv.h" #include "sun4i_crtc.h"
#include "sun4i_tcon.h" #include "sun4i_tcon.h"
#include "sun4i_rgb.h" #include "sun4i_rgb.h"
@ -26,7 +26,7 @@ struct sun4i_rgb {
struct drm_connector connector; struct drm_connector connector;
struct drm_encoder encoder; struct drm_encoder encoder;
struct sun4i_drv *drv; struct sun4i_tcon *tcon;
}; };
static inline struct sun4i_rgb * static inline struct sun4i_rgb *
@ -47,8 +47,7 @@ static int sun4i_rgb_get_modes(struct drm_connector *connector)
{ {
struct sun4i_rgb *rgb = struct sun4i_rgb *rgb =
drm_connector_to_sun4i_rgb(connector); drm_connector_to_sun4i_rgb(connector);
struct sun4i_drv *drv = rgb->drv; struct sun4i_tcon *tcon = rgb->tcon;
struct sun4i_tcon *tcon = drv->tcon;
return drm_panel_get_modes(tcon->panel); 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 drm_display_mode *mode)
{ {
struct sun4i_rgb *rgb = drm_connector_to_sun4i_rgb(connector); struct sun4i_rgb *rgb = drm_connector_to_sun4i_rgb(connector);
struct sun4i_drv *drv = rgb->drv; struct sun4i_tcon *tcon = rgb->tcon;
struct sun4i_tcon *tcon = drv->tcon;
u32 hsync = mode->hsync_end - mode->hsync_start; u32 hsync = mode->hsync_end - mode->hsync_start;
u32 vsync = mode->vsync_end - mode->vsync_start; u32 vsync = mode->vsync_end - mode->vsync_start;
unsigned long rate = mode->clock * 1000; unsigned long rate = mode->clock * 1000;
@ -115,8 +113,7 @@ static void
sun4i_rgb_connector_destroy(struct drm_connector *connector) sun4i_rgb_connector_destroy(struct drm_connector *connector)
{ {
struct sun4i_rgb *rgb = drm_connector_to_sun4i_rgb(connector); struct sun4i_rgb *rgb = drm_connector_to_sun4i_rgb(connector);
struct sun4i_drv *drv = rgb->drv; struct sun4i_tcon *tcon = rgb->tcon;
struct sun4i_tcon *tcon = drv->tcon;
drm_panel_detach(tcon->panel); drm_panel_detach(tcon->panel);
drm_connector_cleanup(connector); 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) static void sun4i_rgb_encoder_enable(struct drm_encoder *encoder)
{ {
struct sun4i_rgb *rgb = drm_encoder_to_sun4i_rgb(encoder); struct sun4i_rgb *rgb = drm_encoder_to_sun4i_rgb(encoder);
struct sun4i_drv *drv = rgb->drv; struct sun4i_tcon *tcon = rgb->tcon;
struct sun4i_tcon *tcon = drv->tcon;
DRM_DEBUG_DRIVER("Enabling RGB output\n"); 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) static void sun4i_rgb_encoder_disable(struct drm_encoder *encoder)
{ {
struct sun4i_rgb *rgb = drm_encoder_to_sun4i_rgb(encoder); struct sun4i_rgb *rgb = drm_encoder_to_sun4i_rgb(encoder);
struct sun4i_drv *drv = rgb->drv; struct sun4i_tcon *tcon = rgb->tcon;
struct sun4i_tcon *tcon = drv->tcon;
DRM_DEBUG_DRIVER("Disabling RGB output\n"); 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 drm_display_mode *adjusted_mode)
{ {
struct sun4i_rgb *rgb = drm_encoder_to_sun4i_rgb(encoder); struct sun4i_rgb *rgb = drm_encoder_to_sun4i_rgb(encoder);
struct sun4i_drv *drv = rgb->drv; struct sun4i_tcon *tcon = rgb->tcon;
struct sun4i_tcon *tcon = drv->tcon;
sun4i_tcon0_mode_set(tcon, mode); sun4i_tcon0_mode_set(tcon, mode);
@ -204,10 +198,8 @@ static struct drm_encoder_funcs sun4i_rgb_enc_funcs = {
.destroy = sun4i_rgb_enc_destroy, .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_encoder *encoder;
struct drm_bridge *bridge; struct drm_bridge *bridge;
struct sun4i_rgb *rgb; 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); rgb = devm_kzalloc(drm->dev, sizeof(*rgb), GFP_KERNEL);
if (!rgb) if (!rgb)
return -ENOMEM; return -ENOMEM;
rgb->drv = drv; rgb->tcon = tcon;
encoder = &rgb->encoder; encoder = &rgb->encoder;
ret = drm_of_find_panel_or_bridge(tcon->dev->of_node, 1, 0, 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 */ /* 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) { if (tcon->panel) {
drm_connector_helper_add(&rgb->connector, drm_connector_helper_add(&rgb->connector,

View File

@ -13,6 +13,6 @@
#ifndef _SUN4I_RGB_H_ #ifndef _SUN4I_RGB_H_
#define _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_ */ #endif /* _SUN4I_RGB_H_ */

View File

@ -142,7 +142,7 @@ void sun4i_tcon0_mode_set(struct sun4i_tcon *tcon,
/* /*
* This is called a backporch in the register documentation, * 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; bp = mode->crtc_htotal - mode->crtc_hsync_start;
DRM_DEBUG_DRIVER("Setting horizontal total %d, backporch %d\n", 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, * 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; bp = mode->crtc_vtotal - mode->crtc_vsync_start;
DRM_DEBUG_DRIVER("Setting vertical total %d, backporch %d\n", 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 sun4i_tcon *tcon = private;
struct drm_device *drm = tcon->drm; struct drm_device *drm = tcon->drm;
struct sun4i_drv *drv = drm->dev_private; struct sun4i_crtc *scrtc = tcon->crtc;
struct sun4i_crtc *scrtc = drv->crtc;
unsigned int status; unsigned int status;
regmap_read(tcon->regs, SUN4I_TCON_GINT0_REG, &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) static void sun4i_tcon_free_clocks(struct sun4i_tcon *tcon)
{ {
sun4i_dclk_free(tcon);
clk_disable_unprepare(tcon->clk); clk_disable_unprepare(tcon->clk);
} }
@ -437,30 +435,45 @@ static int sun4i_tcon_bind(struct device *dev, struct device *master,
return ret; return ret;
} }
ret = sun4i_tcon_init_regmap(dev, tcon);
if (ret) {
dev_err(dev, "Couldn't init our TCON regmap\n");
goto err_assert_reset;
}
ret = sun4i_tcon_init_clocks(dev, tcon); ret = sun4i_tcon_init_clocks(dev, tcon);
if (ret) { if (ret) {
dev_err(dev, "Couldn't init our TCON clocks\n"); dev_err(dev, "Couldn't init our TCON clocks\n");
goto err_assert_reset; goto err_assert_reset;
} }
ret = sun4i_tcon_init_irq(dev, tcon); ret = sun4i_tcon_init_regmap(dev, tcon);
if (ret) { if (ret) {
dev_err(dev, "Couldn't init our TCON interrupts\n"); dev_err(dev, "Couldn't init our TCON regmap\n");
goto err_free_clocks; goto err_free_clocks;
} }
ret = sun4i_rgb_init(drm); ret = sun4i_dclk_create(dev, tcon);
if (ret) {
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, tcon);
if (ret < 0) if (ret < 0)
goto err_free_clocks; goto err_free_clocks;
return 0; return 0;
err_free_dotclock:
sun4i_dclk_free(tcon);
err_free_clocks: err_free_clocks:
sun4i_tcon_free_clocks(tcon); sun4i_tcon_free_clocks(tcon);
err_assert_reset: 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); struct sun4i_tcon *tcon = dev_get_drvdata(dev);
sun4i_dclk_free(tcon);
sun4i_tcon_free_clocks(tcon); sun4i_tcon_free_clocks(tcon);
} }

View File

@ -169,6 +169,9 @@ struct sun4i_tcon {
/* Platform adjustments */ /* Platform adjustments */
const struct sun4i_tcon_quirks *quirks; const struct sun4i_tcon_quirks *quirks;
/* Associated crtc */
struct sun4i_crtc *crtc;
}; };
struct drm_bridge *sun4i_tcon_find_bridge(struct device_node *node); struct drm_bridge *sun4i_tcon_find_bridge(struct device_node *node);

View File

@ -19,9 +19,11 @@
#include <drm/drmP.h> #include <drm/drmP.h>
#include <drm/drm_atomic_helper.h> #include <drm/drm_atomic_helper.h>
#include <drm/drm_crtc_helper.h> #include <drm/drm_crtc_helper.h>
#include <drm/drm_of.h>
#include <drm/drm_panel.h> #include <drm/drm_panel.h>
#include "sun4i_backend.h" #include "sun4i_backend.h"
#include "sun4i_crtc.h"
#include "sun4i_drv.h" #include "sun4i_drv.h"
#include "sun4i_tcon.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) static void sun4i_tv_disable(struct drm_encoder *encoder)
{ {
struct sun4i_tv *tv = drm_encoder_to_sun4i_tv(encoder); struct sun4i_tv *tv = drm_encoder_to_sun4i_tv(encoder);
struct sun4i_drv *drv = tv->drv; struct sun4i_crtc *crtc = drm_crtc_to_sun4i_crtc(encoder->crtc);
struct sun4i_tcon *tcon = drv->tcon; struct sun4i_tcon *tcon = crtc->tcon;
struct sun4i_backend *backend = crtc->backend;
DRM_DEBUG_DRIVER("Disabling the TV Output\n"); 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, regmap_update_bits(tv->regs, SUN4I_TVE_EN_REG,
SUN4I_TVE_EN_ENABLE, SUN4I_TVE_EN_ENABLE,
0); 0);
sun4i_backend_disable_color_correction(drv->backend); sun4i_backend_disable_color_correction(backend);
} }
static void sun4i_tv_enable(struct drm_encoder *encoder) static void sun4i_tv_enable(struct drm_encoder *encoder)
{ {
struct sun4i_tv *tv = drm_encoder_to_sun4i_tv(encoder); struct sun4i_tv *tv = drm_encoder_to_sun4i_tv(encoder);
struct sun4i_drv *drv = tv->drv; struct sun4i_crtc *crtc = drm_crtc_to_sun4i_crtc(encoder->crtc);
struct sun4i_tcon *tcon = drv->tcon; struct sun4i_tcon *tcon = crtc->tcon;
struct sun4i_backend *backend = crtc->backend;
DRM_DEBUG_DRIVER("Enabling the TV Output\n"); 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, regmap_update_bits(tv->regs, SUN4I_TVE_EN_REG,
SUN4I_TVE_EN_ENABLE, 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 drm_display_mode *adjusted_mode)
{ {
struct sun4i_tv *tv = drm_encoder_to_sun4i_tv(encoder); struct sun4i_tv *tv = drm_encoder_to_sun4i_tv(encoder);
struct sun4i_drv *drv = tv->drv; struct sun4i_crtc *crtc = drm_crtc_to_sun4i_crtc(encoder->crtc);
struct sun4i_tcon *tcon = drv->tcon; struct sun4i_tcon *tcon = crtc->tcon;
const struct tv_mode *tv_mode = sun4i_tv_find_tv_by_mode(mode); const struct tv_mode *tv_mode = sun4i_tv_find_tv_by_mode(mode);
sun4i_tcon1_mode_set(tcon, 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; 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, drm_connector_helper_add(&tv->connector,
&sun4i_tv_comp_connector_helper_funcs); &sun4i_tv_comp_connector_helper_funcs);