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:
commit
cb2e77c1d5
@ -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>
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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_ */
|
||||
|
@ -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;
|
||||
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;
|
||||
|
||||
/* 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);
|
||||
}
|
||||
|
||||
|
@ -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_ */
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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_ */
|
||||
|
@ -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,
|
||||
|
@ -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_ */
|
||||
|
@ -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_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);
|
||||
if (ret) {
|
||||
dev_err(dev, "Couldn't init our TCON clocks\n");
|
||||
goto err_assert_reset;
|
||||
}
|
||||
|
||||
ret = sun4i_tcon_init_irq(dev, tcon);
|
||||
ret = sun4i_tcon_init_regmap(dev, tcon);
|
||||
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;
|
||||
}
|
||||
|
||||
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)
|
||||
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);
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
Loading…
Reference in New Issue
Block a user