From patchwork Sun Sep 13 22:50:57 2015 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Laurent Pinchart X-Patchwork-Id: 7171211 Return-Path: X-Original-To: patchwork-dri-devel@patchwork.kernel.org Delivered-To: patchwork-parsemail@patchwork1.web.kernel.org Received: from mail.kernel.org (mail.kernel.org [198.145.29.136]) by patchwork1.web.kernel.org (Postfix) with ESMTP id 7C5D49F54C for ; Sun, 13 Sep 2015 22:51:29 +0000 (UTC) Received: from mail.kernel.org (localhost [127.0.0.1]) by mail.kernel.org (Postfix) with ESMTP id 26FE62066D for ; Sun, 13 Sep 2015 22:51:26 +0000 (UTC) Received: from gabe.freedesktop.org (gabe.freedesktop.org [131.252.210.177]) by mail.kernel.org (Postfix) with ESMTP id 2AF2320638 for ; Sun, 13 Sep 2015 22:51:24 +0000 (UTC) Received: from gabe.freedesktop.org (localhost [127.0.0.1]) by gabe.freedesktop.org (Postfix) with ESMTP id 1F5366E758; Sun, 13 Sep 2015 15:51:23 -0700 (PDT) X-Original-To: dri-devel@lists.freedesktop.org Delivered-To: dri-devel@lists.freedesktop.org Received: from galahad.ideasonboard.com (galahad.ideasonboard.com [185.26.127.97]) by gabe.freedesktop.org (Postfix) with ESMTPS id CA5B26E758 for ; Sun, 13 Sep 2015 15:51:21 -0700 (PDT) Received: from avalon.pp.htv.fi (85-23-193-79.bb.dnainternet.fi [85.23.193.79]) by galahad.ideasonboard.com (Postfix) with ESMTPSA id 9ACFF21C5C; Mon, 14 Sep 2015 00:49:00 +0200 (CEST) From: Laurent Pinchart To: dri-devel@lists.freedesktop.org Subject: [PATCH 10/22] drm: rcar-du: Expose the VSP1 compositor through KMS planes Date: Mon, 14 Sep 2015 01:50:57 +0300 Message-Id: <1442184669-30990-11-git-send-email-laurent.pinchart+renesas@ideasonboard.com> X-Mailer: git-send-email 2.4.6 In-Reply-To: <1442184669-30990-1-git-send-email-laurent.pinchart+renesas@ideasonboard.com> References: <1442184669-30990-1-git-send-email-laurent.pinchart+renesas@ideasonboard.com> Cc: linux-sh@vger.kernel.org X-BeenThere: dri-devel@lists.freedesktop.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: Direct Rendering Infrastructure - Development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Errors-To: dri-devel-bounces@lists.freedesktop.org Sender: "dri-devel" X-Spam-Status: No, score=-4.2 required=5.0 tests=BAYES_00, RCVD_IN_DNSWL_MED, T_RP_MATCHES_RCVD, UNPARSEABLE_RELAY autolearn=unavailable version=3.3.1 X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on mail.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP Signed-off-by: Laurent Pinchart --- drivers/gpu/drm/rcar-du/Kconfig | 7 + drivers/gpu/drm/rcar-du/Makefile | 2 + drivers/gpu/drm/rcar-du/rcar_du_crtc.c | 42 +++- drivers/gpu/drm/rcar-du/rcar_du_crtc.h | 2 + drivers/gpu/drm/rcar-du/rcar_du_drv.h | 4 + drivers/gpu/drm/rcar-du/rcar_du_kms.c | 28 ++- drivers/gpu/drm/rcar-du/rcar_du_plane.c | 7 +- drivers/gpu/drm/rcar-du/rcar_du_plane.h | 11 +- drivers/gpu/drm/rcar-du/rcar_du_vsp.c | 359 ++++++++++++++++++++++++++++++++ drivers/gpu/drm/rcar-du/rcar_du_vsp.h | 72 +++++++ 10 files changed, 518 insertions(+), 16 deletions(-) create mode 100644 drivers/gpu/drm/rcar-du/rcar_du_vsp.c create mode 100644 drivers/gpu/drm/rcar-du/rcar_du_vsp.h diff --git a/drivers/gpu/drm/rcar-du/Kconfig b/drivers/gpu/drm/rcar-du/Kconfig index d4e0a39568f6..62650abc3120 100644 --- a/drivers/gpu/drm/rcar-du/Kconfig +++ b/drivers/gpu/drm/rcar-du/Kconfig @@ -25,3 +25,10 @@ config DRM_RCAR_LVDS help Enable support for the R-Car Display Unit embedded LVDS encoders (currently only on R8A7790 and R8A7791). + +config DRM_RCAR_VSP + bool "R-Car DU VSP Compositor Support" + depends on DRM_RCAR_DU + depends on VIDEO_RENESAS_VSP1 + help + Enable support to expose the R-Car VSP Compositor as KMS planes. diff --git a/drivers/gpu/drm/rcar-du/Makefile b/drivers/gpu/drm/rcar-du/Makefile index 05de1c4097af..827711e28226 100644 --- a/drivers/gpu/drm/rcar-du/Makefile +++ b/drivers/gpu/drm/rcar-du/Makefile @@ -11,4 +11,6 @@ rcar-du-drm-$(CONFIG_DRM_RCAR_HDMI) += rcar_du_hdmicon.o \ rcar_du_hdmienc.o rcar-du-drm-$(CONFIG_DRM_RCAR_LVDS) += rcar_du_lvdsenc.o +rcar-du-drm-$(CONFIG_DRM_RCAR_VSP) += rcar_du_vsp.o + obj-$(CONFIG_DRM_RCAR_DU) += rcar-du-drm.o diff --git a/drivers/gpu/drm/rcar-du/rcar_du_crtc.c b/drivers/gpu/drm/rcar-du/rcar_du_crtc.c index 7e2f5c26d589..196b940ea8d7 100644 --- a/drivers/gpu/drm/rcar-du/rcar_du_crtc.c +++ b/drivers/gpu/drm/rcar-du/rcar_du_crtc.c @@ -28,6 +28,7 @@ #include "rcar_du_kms.h" #include "rcar_du_plane.h" #include "rcar_du_regs.h" +#include "rcar_du_vsp.h" static u32 rcar_du_crtc_read(struct rcar_du_crtc *rcrtc, u32 reg) { @@ -207,6 +208,7 @@ plane_format(struct rcar_du_plane *plane) static void rcar_du_crtc_update_planes(struct rcar_du_crtc *rcrtc) { struct rcar_du_plane *planes[RCAR_DU_NUM_HW_PLANES]; + struct rcar_du_device *rcdu = rcrtc->group->dev; unsigned int num_planes = 0; unsigned int dptsr_planes; unsigned int hwplanes = 0; @@ -250,6 +252,12 @@ static void rcar_du_crtc_update_planes(struct rcar_du_crtc *rcrtc) } } + /* If VSP+DU integration is enabled the plane assignment is fixed. */ + if (rcar_du_has(rcdu, RCAR_DU_FEATURE_VSP1_SOURCE)) { + dspr = (rcrtc->index % 2) + 1; + hwplanes = 1 << (rcrtc->index % 2); + } + /* Update the planes to display timing and dot clock generator * associations. * @@ -389,6 +397,10 @@ static void rcar_du_crtc_start(struct rcar_du_crtc *rcrtc) rcar_du_group_start_stop(rcrtc->group, true); + /* Enable the VSP compositor. */ + if (rcar_du_has(rcrtc->group->dev, RCAR_DU_FEATURE_VSP1_SOURCE)) + rcar_du_vsp_enable(rcrtc); + /* Turn vertical blanking interrupt reporting back on. */ drm_crtc_vblank_on(crtc); @@ -422,6 +434,10 @@ static void rcar_du_crtc_stop(struct rcar_du_crtc *rcrtc) rcar_du_crtc_wait_page_flip(rcrtc); drm_crtc_vblank_off(crtc); + /* Disable the VSP compositor. */ + if (rcar_du_has(rcrtc->group->dev, RCAR_DU_FEATURE_VSP1_SOURCE)) + rcar_du_vsp_disable(rcrtc); + /* Select switch sync mode. This stops display operation and configures * the HSYNC and VSYNC signals as inputs. */ @@ -434,6 +450,9 @@ static void rcar_du_crtc_stop(struct rcar_du_crtc *rcrtc) void rcar_du_crtc_suspend(struct rcar_du_crtc *rcrtc) { + if (rcar_du_has(rcrtc->group->dev, RCAR_DU_FEATURE_VSP1_SOURCE)) + rcar_du_vsp_disable(rcrtc); + rcar_du_crtc_stop(rcrtc); rcar_du_crtc_put(rcrtc); } @@ -449,13 +468,17 @@ void rcar_du_crtc_resume(struct rcar_du_crtc *rcrtc) rcar_du_crtc_start(rcrtc); /* Commit the planes state. */ - for (i = 0; i < rcrtc->group->num_planes; ++i) { - struct rcar_du_plane *plane = &rcrtc->group->planes[i]; + if (rcar_du_has(rcrtc->group->dev, RCAR_DU_FEATURE_VSP1_SOURCE)) { + rcar_du_vsp_enable(rcrtc); + } else { + for (i = 0; i < rcrtc->group->num_planes; ++i) { + struct rcar_du_plane *plane = &rcrtc->group->planes[i]; - if (plane->plane.state->crtc != &rcrtc->crtc) - continue; + if (plane->plane.state->crtc != &rcrtc->crtc) + continue; - rcar_du_plane_setup(plane); + rcar_du_plane_setup(plane); + } } rcar_du_crtc_update_planes(rcrtc); @@ -578,6 +601,7 @@ int rcar_du_crtc_create(struct rcar_du_group *rgrp, unsigned int index) struct platform_device *pdev = to_platform_device(rcdu->dev); struct rcar_du_crtc *rcrtc = &rcdu->crtcs[index]; struct drm_crtc *crtc = &rcrtc->crtc; + struct drm_plane *primary; unsigned int irqflags; struct clk *clk; char clk_name[9]; @@ -615,8 +639,12 @@ int rcar_du_crtc_create(struct rcar_du_group *rgrp, unsigned int index) rcrtc->index = index; rcrtc->enabled = false; - ret = drm_crtc_init_with_planes(rcdu->ddev, crtc, - &rgrp->planes[index % 2].plane, + if (rcar_du_has(rcdu, RCAR_DU_FEATURE_VSP1_SOURCE)) + primary = &rcrtc->vsp->planes[0].plane; + else + primary = &rgrp->planes[index % 2].plane; + + ret = drm_crtc_init_with_planes(rcdu->ddev, crtc, primary, NULL, &crtc_funcs); if (ret < 0) return ret; diff --git a/drivers/gpu/drm/rcar-du/rcar_du_crtc.h b/drivers/gpu/drm/rcar-du/rcar_du_crtc.h index 4b95d9d08c49..c7ab46702b1d 100644 --- a/drivers/gpu/drm/rcar-du/rcar_du_crtc.h +++ b/drivers/gpu/drm/rcar-du/rcar_du_crtc.h @@ -21,6 +21,7 @@ #include struct rcar_du_group; +struct rcar_du_vsp; /** * struct rcar_du_crtc - the CRTC, representing a DU superposition processor @@ -52,6 +53,7 @@ struct rcar_du_crtc { bool enabled; struct rcar_du_group *group; + struct rcar_du_vsp *vsp; }; #define to_rcar_crtc(c) container_of(c, struct rcar_du_crtc, crtc) diff --git a/drivers/gpu/drm/rcar-du/rcar_du_drv.h b/drivers/gpu/drm/rcar-du/rcar_du_drv.h index e10b4f0d8f83..a81eb3281e7f 100644 --- a/drivers/gpu/drm/rcar-du/rcar_du_drv.h +++ b/drivers/gpu/drm/rcar-du/rcar_du_drv.h @@ -19,6 +19,7 @@ #include "rcar_du_crtc.h" #include "rcar_du_group.h" +#include "rcar_du_vsp.h" struct clk; struct device; @@ -29,6 +30,7 @@ struct rcar_du_lvdsenc; #define RCAR_DU_FEATURE_CRTC_IRQ_CLOCK (1 << 0) /* Per-CRTC IRQ and clock */ #define RCAR_DU_FEATURE_EXT_CTRL_REGS (1 << 1) /* Has extended control registers */ +#define RCAR_DU_FEATURE_VSP1_SOURCE (1 << 2) /* Has inputs from VSP1 */ #define RCAR_DU_QUIRK_ALIGN_128B (1 << 0) /* Align pitches to 128 bytes */ #define RCAR_DU_QUIRK_LVDS_LANES (1 << 1) /* LVDS lanes 1 and 3 inverted */ @@ -68,6 +70,7 @@ struct rcar_du_device_info { #define RCAR_DU_MAX_CRTCS 3 #define RCAR_DU_MAX_GROUPS DIV_ROUND_UP(RCAR_DU_MAX_CRTCS, 2) #define RCAR_DU_MAX_LVDS 2 +#define RCAR_DU_MAX_VSPS 4 struct rcar_du_device { struct device *dev; @@ -82,6 +85,7 @@ struct rcar_du_device { unsigned int num_crtcs; struct rcar_du_group groups[RCAR_DU_MAX_GROUPS]; + struct rcar_du_vsp vsps[RCAR_DU_MAX_VSPS]; struct { struct drm_property *alpha; diff --git a/drivers/gpu/drm/rcar-du/rcar_du_kms.c b/drivers/gpu/drm/rcar-du/rcar_du_kms.c index 6196410b9e98..3f3d93dcbf64 100644 --- a/drivers/gpu/drm/rcar-du/rcar_du_kms.c +++ b/drivers/gpu/drm/rcar-du/rcar_du_kms.c @@ -28,6 +28,7 @@ #include "rcar_du_kms.h" #include "rcar_du_lvdsenc.h" #include "rcar_du_regs.h" +#include "rcar_du_vsp.h" /* ----------------------------------------------------------------------------- * Format helpers @@ -195,12 +196,16 @@ static void rcar_du_output_poll_changed(struct drm_device *dev) static int rcar_du_atomic_check(struct drm_device *dev, struct drm_atomic_state *state) { + struct rcar_du_device *rcdu = dev->dev_private; int ret; ret = drm_atomic_helper_check(dev, state); if (ret < 0) return ret; + if (rcar_du_has(rcdu, RCAR_DU_FEATURE_VSP1_SOURCE)) + return 0; + return rcar_du_atomic_check_planes(dev, state); } @@ -544,9 +549,26 @@ int rcar_du_modeset_init(struct rcar_du_device *rcdu) */ rgrp->dptsr_planes = rgrp->num_crtcs > 1 ? 0xf0 : 0; - ret = rcar_du_planes_init(rgrp); - if (ret < 0) - return ret; + if (!rcar_du_has(rcdu, RCAR_DU_FEATURE_VSP1_SOURCE)) { + ret = rcar_du_planes_init(rgrp); + if (ret < 0) + return ret; + } + } + + /* Initialize the compositors. */ + if (rcar_du_has(rcdu, RCAR_DU_FEATURE_VSP1_SOURCE)) { + for (i = 0; i < rcdu->num_crtcs; ++i) { + struct rcar_du_vsp *vsp = &rcdu->vsps[i]; + + vsp->index = i; + vsp->dev = rcdu; + rcdu->crtcs[i].vsp = vsp; + + ret = rcar_du_vsp_init(vsp); + if (ret < 0) + return ret; + } } /* Create the CRTCs. */ diff --git a/drivers/gpu/drm/rcar-du/rcar_du_plane.c b/drivers/gpu/drm/rcar-du/rcar_du_plane.c index b868184e8385..4a38ced4b952 100644 --- a/drivers/gpu/drm/rcar-du/rcar_du_plane.c +++ b/drivers/gpu/drm/rcar-du/rcar_du_plane.c @@ -505,12 +505,9 @@ static void rcar_du_plane_setup_format(struct rcar_du_group *rgrp, rcar_du_plane_write(rgrp, index, PnMLR, 0); } -void rcar_du_plane_setup(struct rcar_du_plane *plane) +void __rcar_du_plane_setup(struct rcar_du_group *rgrp, + const struct rcar_du_plane_state *state) { - struct rcar_du_plane_state *state = - to_rcar_plane_state(plane->plane.state); - struct rcar_du_group *rgrp = plane->group; - rcar_du_plane_setup_format(rgrp, state->hwindex, state); if (state->format->planes == 2) rcar_du_plane_setup_format(rgrp, (state->hwindex + 1) % 8, diff --git a/drivers/gpu/drm/rcar-du/rcar_du_plane.h b/drivers/gpu/drm/rcar-du/rcar_du_plane.h index 6a6460dffae4..b18b7b25dbfa 100644 --- a/drivers/gpu/drm/rcar-du/rcar_du_plane.h +++ b/drivers/gpu/drm/rcar-du/rcar_du_plane.h @@ -76,6 +76,15 @@ int rcar_du_atomic_check_planes(struct drm_device *dev, int rcar_du_planes_init(struct rcar_du_group *rgrp); -void rcar_du_plane_setup(struct rcar_du_plane *plane); +void __rcar_du_plane_setup(struct rcar_du_group *rgrp, + const struct rcar_du_plane_state *state); + +static inline void rcar_du_plane_setup(struct rcar_du_plane *plane) +{ + struct rcar_du_plane_state *state = + to_rcar_plane_state(plane->plane.state); + + return __rcar_du_plane_setup(plane->group, state); +} #endif /* __RCAR_DU_PLANE_H__ */ diff --git a/drivers/gpu/drm/rcar-du/rcar_du_vsp.c b/drivers/gpu/drm/rcar-du/rcar_du_vsp.c new file mode 100644 index 000000000000..6e34dfd0ef42 --- /dev/null +++ b/drivers/gpu/drm/rcar-du/rcar_du_vsp.c @@ -0,0 +1,359 @@ +/* + * rcar_du_vsp.h -- R-Car Display Unit VSP-Based Compositor + * + * Copyright (C) 2015 Renesas Electronics Corporation + * + * Contact: Laurent Pinchart (laurent.pinchart@ideasonboard.com) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + */ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include + +#include "rcar_du_drv.h" +#include "rcar_du_kms.h" +#include "rcar_du_vsp.h" + +void rcar_du_vsp_enable(struct rcar_du_crtc *crtc) +{ + const struct drm_display_mode *mode = &crtc->crtc.state->adjusted_mode; + struct rcar_du_plane_state state = { + .state = { + .crtc = &crtc->crtc, + .crtc_x = 0, + .crtc_y = 0, + .crtc_w = mode->hdisplay, + .crtc_h = mode->vdisplay, + .src_x = 0, + .src_y = 0, + .src_w = mode->hdisplay << 16, + .src_h = mode->vdisplay << 16, + }, + .format = rcar_du_format_info(DRM_FORMAT_ARGB8888), + .hwindex = crtc->index % 2, + .source = RCAR_DU_PLANE_VSPD1, + .alpha = 255, + .colorkey = 0, + .zpos = 0, + }; + + __rcar_du_plane_setup(crtc->group, &state); + + /* Ensure that the plane source configuration takes effect by requesting + * a restart of the group. See rcar_du_plane_atomic_update() for a more + * detailed explanation. + * + * TODO: Check whether this is still needed on Gen3. + */ + crtc->group->need_restart = true; + + vsp1_du_setup_lif(crtc->vsp->vsp, mode->hdisplay, mode->vdisplay); +} + +void rcar_du_vsp_disable(struct rcar_du_crtc *crtc) +{ + vsp1_du_setup_lif(crtc->vsp->vsp, 0, 0); +} + +/* Keep the two tables in sync. */ +static const u32 formats_kms[] = { + DRM_FORMAT_RGB332, + DRM_FORMAT_ARGB4444, + DRM_FORMAT_XRGB4444, + DRM_FORMAT_ARGB1555, + DRM_FORMAT_XRGB1555, + DRM_FORMAT_RGB565, + DRM_FORMAT_BGR888, + DRM_FORMAT_RGB888, + DRM_FORMAT_BGRA8888, + DRM_FORMAT_BGRX8888, + DRM_FORMAT_ARGB8888, + DRM_FORMAT_XRGB8888, + DRM_FORMAT_UYVY, + DRM_FORMAT_VYUY, + DRM_FORMAT_YUYV, + DRM_FORMAT_YVYU, + DRM_FORMAT_NV12, + DRM_FORMAT_NV21, + DRM_FORMAT_NV16, + DRM_FORMAT_NV61, +}; + +static const u32 formats_v4l2[] = { + V4L2_PIX_FMT_RGB332, + V4L2_PIX_FMT_ARGB444, + V4L2_PIX_FMT_XRGB444, + V4L2_PIX_FMT_ARGB555, + V4L2_PIX_FMT_XRGB555, + V4L2_PIX_FMT_RGB565, + V4L2_PIX_FMT_RGB24, + V4L2_PIX_FMT_BGR24, + V4L2_PIX_FMT_ARGB32, + V4L2_PIX_FMT_XRGB32, + V4L2_PIX_FMT_ABGR32, + V4L2_PIX_FMT_XBGR32, + V4L2_PIX_FMT_UYVY, + V4L2_PIX_FMT_VYUY, + V4L2_PIX_FMT_YUYV, + V4L2_PIX_FMT_YVYU, + V4L2_PIX_FMT_NV12M, + V4L2_PIX_FMT_NV21M, + V4L2_PIX_FMT_NV16M, + V4L2_PIX_FMT_NV61M, +}; + +static void rcar_du_vsp_plane_setup(struct rcar_du_vsp_plane *plane) +{ + struct rcar_du_vsp_plane_state *state = + to_rcar_vsp_plane_state(plane->plane.state); + struct drm_framebuffer *fb = plane->plane.state->fb; + struct drm_gem_cma_object *gem; + struct v4l2_rect src; + struct v4l2_rect dst; + dma_addr_t paddr[2] = { 0, }; + u32 pixelformat = 0; + unsigned int i; + + src.left = state->state.src_x >> 16; + src.top = state->state.src_y >> 16; + src.width = state->state.src_w >> 16; + src.height = state->state.src_h >> 16; + + dst.left = state->state.crtc_x; + dst.top = state->state.crtc_y; + dst.width = state->state.crtc_w; + dst.height = state->state.crtc_h; + + gem = drm_fb_cma_get_gem_obj(fb, 0); + paddr[0] = gem->paddr + fb->offsets[0]; + + if (state->format->planes == 2) { + gem = drm_fb_cma_get_gem_obj(fb, 1); + paddr[1] = gem->paddr + fb->offsets[1]; + } + + for (i = 0; i < ARRAY_SIZE(formats_kms); ++i) { + if (formats_kms[i] == state->format->fourcc) { + pixelformat = formats_v4l2[i]; + break; + } + } + + WARN_ON(!pixelformat); + + vsp1_du_setup_rpf(plane->vsp->vsp, plane->index, pixelformat, + fb->pitches[0], paddr, &src, &dst); +} + +static int rcar_du_vsp_plane_atomic_check(struct drm_plane *plane, + struct drm_plane_state *state) +{ + struct rcar_du_vsp_plane_state *rstate = to_rcar_vsp_plane_state(state); + struct rcar_du_vsp_plane *rplane = to_rcar_vsp_plane(plane); + struct rcar_du_device *rcdu = rplane->vsp->dev; + + if (!state->fb || !state->crtc) { + rstate->format = NULL; + return 0; + } + + if (state->src_w >> 16 != state->crtc_w || + state->src_h >> 16 != state->crtc_h) { + dev_dbg(rcdu->dev, "%s: scaling not supported\n", __func__); + return -EINVAL; + } + + rstate->format = rcar_du_format_info(state->fb->pixel_format); + if (rstate->format == NULL) { + dev_dbg(rcdu->dev, "%s: unsupported format %08x\n", __func__, + state->fb->pixel_format); + return -EINVAL; + } + + return 0; +} + +static void rcar_du_vsp_plane_atomic_update(struct drm_plane *plane, + struct drm_plane_state *old_state) +{ + struct rcar_du_vsp_plane *rplane = to_rcar_vsp_plane(plane); + + if (plane->state->crtc) + rcar_du_vsp_plane_setup(rplane); + else + vsp1_du_setup_rpf(rplane->vsp->vsp, rplane->index, 0, 0, 0, + NULL, NULL); +} + +static const struct drm_plane_helper_funcs rcar_du_vsp_plane_helper_funcs = { + .atomic_check = rcar_du_vsp_plane_atomic_check, + .atomic_update = rcar_du_vsp_plane_atomic_update, +}; + +static struct drm_plane_state * +rcar_du_vsp_plane_atomic_duplicate_state(struct drm_plane *plane) +{ + struct rcar_du_vsp_plane_state *state; + struct rcar_du_vsp_plane_state *copy; + + if (WARN_ON(!plane->state)) + return NULL; + + state = to_rcar_vsp_plane_state(plane->state); + copy = kmemdup(state, sizeof(*state), GFP_KERNEL); + if (copy == NULL) + return NULL; + + __drm_atomic_helper_plane_duplicate_state(plane, ©->state); + + return ©->state; +} + +static void rcar_du_vsp_plane_atomic_destroy_state(struct drm_plane *plane, + struct drm_plane_state *state) +{ + __drm_atomic_helper_plane_destroy_state(plane, state); + kfree(to_rcar_vsp_plane_state(state)); +} + +static void rcar_du_vsp_plane_reset(struct drm_plane *plane) +{ + struct rcar_du_vsp_plane_state *state; + + if (plane->state) { + rcar_du_vsp_plane_atomic_destroy_state(plane, plane->state); + plane->state = NULL; + } + + state = kzalloc(sizeof(*state), GFP_KERNEL); + if (state == NULL) + return; + + state->alpha = 255; + + plane->state = &state->state; + plane->state->plane = plane; +} + +static int rcar_du_vsp_plane_atomic_set_property(struct drm_plane *plane, + struct drm_plane_state *state, struct drm_property *property, + uint64_t val) +{ + struct rcar_du_vsp_plane_state *rstate = to_rcar_vsp_plane_state(state); + struct rcar_du_device *rcdu = to_rcar_vsp_plane(plane)->vsp->dev; + + if (property == rcdu->props.alpha) + rstate->alpha = val; + else + return -EINVAL; + + return 0; +} + +static int rcar_du_vsp_plane_atomic_get_property(struct drm_plane *plane, + const struct drm_plane_state *state, struct drm_property *property, + uint64_t *val) +{ + const struct rcar_du_vsp_plane_state *rstate = + container_of(state, const struct rcar_du_vsp_plane_state, state); + struct rcar_du_device *rcdu = to_rcar_vsp_plane(plane)->vsp->dev; + + if (property == rcdu->props.alpha) + *val = rstate->alpha; + else + return -EINVAL; + + return 0; +} + +static const struct drm_plane_funcs rcar_du_vsp_plane_funcs = { + .update_plane = drm_atomic_helper_update_plane, + .disable_plane = drm_atomic_helper_disable_plane, + .reset = rcar_du_vsp_plane_reset, + .set_property = drm_atomic_helper_plane_set_property, + .destroy = drm_plane_cleanup, + .atomic_duplicate_state = rcar_du_vsp_plane_atomic_duplicate_state, + .atomic_destroy_state = rcar_du_vsp_plane_atomic_destroy_state, + .atomic_set_property = rcar_du_vsp_plane_atomic_set_property, + .atomic_get_property = rcar_du_vsp_plane_atomic_get_property, +}; + +int rcar_du_vsp_init(struct rcar_du_vsp *vsp) +{ + struct rcar_du_device *rcdu = vsp->dev; + struct platform_device *pdev; + struct device_node *np; + unsigned int i; + int ret; + + /* Find the VSP device and initialize it. */ + np = of_parse_phandle(rcdu->dev->of_node, "vsps", vsp->index); + if (!np) { + dev_err(rcdu->dev, "vsps node not found\n"); + return -ENXIO; + } + + pdev = of_find_device_by_node(np); + of_node_put(np); + if (!pdev) + return -ENXIO; + + vsp->vsp = &pdev->dev; + + ret = vsp1_du_init(vsp->vsp); + if (ret < 0) + return ret; + + /* The VSP2D (Gen3) has 5 RPFs, but the VSP1D (Gen2) is limited to + * 4 RPFs. Hardcode the number of planes to 4 as Gen3 isn't supported + * yet. + */ + vsp->num_planes = 4; + + vsp->planes = devm_kcalloc(rcdu->dev, vsp->num_planes, + sizeof(*vsp->planes), GFP_KERNEL); + if (!vsp->planes) + return -ENOMEM; + + for (i = 0; i < vsp->num_planes; ++i) { + enum drm_plane_type type = i ? DRM_PLANE_TYPE_OVERLAY + : DRM_PLANE_TYPE_PRIMARY; + struct rcar_du_vsp_plane *plane = &vsp->planes[i]; + + plane->vsp = vsp; + plane->index = i; + + ret = drm_universal_plane_init(rcdu->ddev, &plane->plane, + 1 << vsp->index, + &rcar_du_vsp_plane_funcs, + formats_kms, + ARRAY_SIZE(formats_kms), type); + if (ret < 0) + return ret; + + drm_plane_helper_add(&plane->plane, + &rcar_du_vsp_plane_helper_funcs); + + if (type == DRM_PLANE_TYPE_PRIMARY) + continue; + + drm_object_attach_property(&plane->plane.base, + rcdu->props.alpha, 255); + } + + return 0; +} diff --git a/drivers/gpu/drm/rcar-du/rcar_du_vsp.h b/drivers/gpu/drm/rcar-du/rcar_du_vsp.h new file mode 100644 index 000000000000..7a6ed21ebcd3 --- /dev/null +++ b/drivers/gpu/drm/rcar-du/rcar_du_vsp.h @@ -0,0 +1,72 @@ +/* + * rcar_du_vsp.h -- R-Car Display Unit VSP-Based Compositor + * + * Copyright (C) 2015 Renesas Electronics Corporation + * + * Contact: Laurent Pinchart (laurent.pinchart@ideasonboard.com) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + */ + +#ifndef __RCAR_DU_VSP_H__ +#define __RCAR_DU_VSP_H__ + +#include +#include + +struct rcar_du_format_info; +struct rcar_du_vsp; + +struct rcar_du_vsp_plane { + struct drm_plane plane; + struct rcar_du_vsp *vsp; + unsigned int index; +}; + +struct rcar_du_vsp { + unsigned int index; + struct device *vsp; + struct rcar_du_device *dev; + struct rcar_du_vsp_plane *planes; + unsigned int num_planes; +}; + +static inline struct rcar_du_vsp_plane *to_rcar_vsp_plane(struct drm_plane *p) +{ + return container_of(p, struct rcar_du_vsp_plane, plane); +} + +/** + * struct rcar_du_vsp_plane_state - Driver-specific plane state + * @state: base DRM plane state + * @format: information about the pixel format used by the plane + * @alpha: value of the plane alpha property + */ +struct rcar_du_vsp_plane_state { + struct drm_plane_state state; + + const struct rcar_du_format_info *format; + + unsigned int alpha; +}; + +static inline struct rcar_du_vsp_plane_state * +to_rcar_vsp_plane_state(struct drm_plane_state *state) +{ + return container_of(state, struct rcar_du_vsp_plane_state, state); +} + +#ifdef CONFIG_DRM_RCAR_VSP +int rcar_du_vsp_init(struct rcar_du_vsp *vsp); +void rcar_du_vsp_enable(struct rcar_du_crtc *crtc); +void rcar_du_vsp_disable(struct rcar_du_crtc *crtc); +#else +static inline int rcar_du_vsp_init(struct rcar_du_vsp *vsp) { return 0; }; +static inline void rcar_du_vsp_enable(struct rcar_du_crtc *crtc) { }; +static inline void rcar_du_vsp_disable(struct rcar_du_crtc *crtc) { }; +#endif + +#endif /* __RCAR_DU_VSP_H__ */