From patchwork Sun Dec 3 10:57:34 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Laurent Pinchart X-Patchwork-Id: 10089191 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork.web.codeaurora.org (Postfix) with ESMTP id 59924602C8 for ; Sun, 3 Dec 2017 10:58:12 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 52D92290BE for ; Sun, 3 Dec 2017 10:58:12 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 47D13290C2; Sun, 3 Dec 2017 10:58:12 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-4.1 required=2.0 tests=BAYES_00,DKIM_SIGNED, RCVD_IN_DNSWL_MED,T_DKIM_INVALID autolearn=ham version=3.3.1 Received: from gabe.freedesktop.org (gabe.freedesktop.org [131.252.210.177]) (using TLSv1.2 with cipher DHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.wl.linuxfoundation.org (Postfix) with ESMTPS id B3863290BE for ; Sun, 3 Dec 2017 10:58:11 +0000 (UTC) Received: from gabe.freedesktop.org (localhost [127.0.0.1]) by gabe.freedesktop.org (Postfix) with ESMTP id EBCAF6E2CC; Sun, 3 Dec 2017 10:57:45 +0000 (UTC) X-Original-To: dri-devel@lists.freedesktop.org Delivered-To: dri-devel@lists.freedesktop.org Received: from galahad.ideasonboard.com (galahad.ideasonboard.com [IPv6:2001:4b98:dc2:45:216:3eff:febb:480d]) by gabe.freedesktop.org (Postfix) with ESMTPS id A89F26E2C5 for ; Sun, 3 Dec 2017 10:57:43 +0000 (UTC) Received: from avalon.bb.dnainternet.fi (dfj612ybrt5fhg77mgycy-3.rev.dnainternet.fi [IPv6:2001:14ba:21f5:5b00:2e86:4862:ef6a:2804]) by galahad.ideasonboard.com (Postfix) with ESMTPSA id 74F61208A5; Sun, 3 Dec 2017 11:55:53 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1512298553; bh=rU8AMqP+DasUzLj28L92bsyFJ7+8fzV5lkvJpUivKFI=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=egGyNE3hhDSQ2VItzbtkpX82NGVj6Z37Gk609iEwFk+41Tx1zcjZkRB8oKnGpct6g kM2rHtqpbfxwkm2e7MN9CYxCLBvFSi2N6AVqtBk+Q37FOUm2cGhKlEMdnTFIjdOEpF g7HebmA4JbxtvLaDi9Z/jxuAbjTqNKKiAvzjXV9k= From: Laurent Pinchart To: linux-media@vger.kernel.org, dri-devel@lists.freedesktop.org Subject: [PATCH 8/9] v4l: vsp1: Integrate DISCOM in display pipeline Date: Sun, 3 Dec 2017 12:57:34 +0200 Message-Id: <20171203105735.10529-9-laurent.pinchart+renesas@ideasonboard.com> X-Mailer: git-send-email 2.13.6 In-Reply-To: <20171203105735.10529-1-laurent.pinchart+renesas@ideasonboard.com> References: <20171203105735.10529-1-laurent.pinchart+renesas@ideasonboard.com> Cc: linux-renesas-soc@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-Virus-Scanned: ClamAV using ClamSMTP The DISCOM is used to compute CRCs on display frames. Integrate it in the display pipeline at the output of the blending unit to process output frames. Computing CRCs on input frames is possible by positioning the DISCOM at a different point in the pipeline. This use case isn't supported at the moment and could be implemented by extending the API between the VSP1 and DU drivers if needed. Signed-off-by: Laurent Pinchart --- drivers/media/platform/vsp1/vsp1_drm.c | 113 +++++++++++++++++++++++++++++++-- drivers/media/platform/vsp1/vsp1_drm.h | 12 ++++ 2 files changed, 121 insertions(+), 4 deletions(-) diff --git a/drivers/media/platform/vsp1/vsp1_drm.c b/drivers/media/platform/vsp1/vsp1_drm.c index 97d2be3b0023..bcf30c25ccb3 100644 --- a/drivers/media/platform/vsp1/vsp1_drm.c +++ b/drivers/media/platform/vsp1/vsp1_drm.c @@ -26,6 +26,7 @@ #include "vsp1_lif.h" #include "vsp1_pipe.h" #include "vsp1_rwpf.h" +#include "vsp1_uif.h" /* ----------------------------------------------------------------------------- @@ -36,9 +37,15 @@ static void vsp1_du_pipeline_frame_end(struct vsp1_pipeline *pipe, bool completed) { struct vsp1_drm_pipeline *drm_pipe = to_vsp1_drm_pipeline(pipe); + u32 crc = 0; - if (drm_pipe->du_complete) - drm_pipe->du_complete(drm_pipe->du_private, completed, 0); + if (!drm_pipe->du_complete) + return; + + if (drm_pipe->uif) + crc = vsp1_uif_get_crc(to_uif(&drm_pipe->uif->subdev)); + + drm_pipe->du_complete(drm_pipe->du_private, completed, crc); } /* ----------------------------------------------------------------------------- @@ -393,9 +400,67 @@ int vsp1_du_atomic_update(struct device *dev, unsigned int pipe_index, } EXPORT_SYMBOL_GPL(vsp1_du_atomic_update); +/* + * Insert the UIF in the pipeline between the prev and next entities. If no UIF + * is available connect the two entities directly. + */ +static int vsp1_du_insert_uif(struct vsp1_device *vsp1, + struct vsp1_pipeline *pipe, + struct vsp1_entity *uif, + struct vsp1_entity *prev, unsigned int prev_pad, + struct vsp1_entity *next, unsigned int next_pad) +{ + int ret; + + if (uif) { + struct v4l2_subdev_format format; + + prev->sink = uif; + prev->sink_pad = UIF_PAD_SINK; + + memset(&format, 0, sizeof(format)); + format.which = V4L2_SUBDEV_FORMAT_ACTIVE; + format.pad = prev_pad; + + ret = v4l2_subdev_call(&prev->subdev, pad, get_fmt, NULL, + &format); + if (ret < 0) + return ret; + + format.pad = UIF_PAD_SINK; + + ret = v4l2_subdev_call(&uif->subdev, pad, set_fmt, NULL, + &format); + if (ret < 0) + return ret; + + dev_dbg(vsp1->dev, "%s: set format %ux%u (%x) on UIF sink\n", + __func__, format.format.width, format.format.height, + format.format.code); + + /* + * The UIF doesn't mangle the format between its sink and + * source pads, so there is no need to retrieve the format on + * its source pad. + */ + + uif->sink = next; + uif->sink_pad = next_pad; + + list_add_tail(&uif->list_pipe, &pipe->entities); + } else { + prev->sink = next; + prev->sink_pad = next_pad; + } + + return 0; +} + static int vsp1_du_setup_rpf_pipe(struct vsp1_device *vsp1, struct vsp1_pipeline *pipe, - struct vsp1_rwpf *rpf, unsigned int bru_input) + struct vsp1_rwpf *rpf, + struct vsp1_entity *uif, + unsigned int bru_input) { struct v4l2_subdev_selection sel; struct v4l2_subdev_format format; @@ -468,6 +533,12 @@ static int vsp1_du_setup_rpf_pipe(struct vsp1_device *vsp1, if (ret < 0) return ret; + /* Insert and configure the UIF if available. */ + ret = vsp1_du_insert_uif(vsp1, pipe, uif, &rpf->entity, RWPF_PAD_SOURCE, + pipe->bru, bru_input); + if (ret < 0) + return ret; + /* BRU sink, propagate the format from the RPF source. */ format.pad = bru_input; @@ -517,6 +588,7 @@ void vsp1_du_atomic_flush(struct device *dev, unsigned int pipe_index, struct vsp1_bru *bru = to_bru(&pipe->bru->subdev); struct vsp1_entity *entity; struct vsp1_entity *next; + struct vsp1_entity *uif; struct vsp1_dl_list *dl; const char *bru_name; unsigned int i; @@ -556,6 +628,12 @@ void vsp1_du_atomic_flush(struct device *dev, unsigned int pipe_index, inputs[j] = rpf; } + /* + * Remove the UIF from the pipeline, it will be inserted only if needed. + */ + if (drm_pipe->uif && !list_empty(&drm_pipe->uif->list_pipe)) + list_del_init(&drm_pipe->uif->list_pipe); + /* Setup the RPF input pipeline for every enabled input. */ for (i = 0; i < pipe->bru->source_pad; ++i) { struct vsp1_rwpf *rpf = inputs[i]; @@ -576,13 +654,29 @@ void vsp1_du_atomic_flush(struct device *dev, unsigned int pipe_index, dev_dbg(vsp1->dev, "%s: connecting RPF.%u to %s:%u\n", __func__, rpf->entity.index, bru_name, i); - ret = vsp1_du_setup_rpf_pipe(vsp1, pipe, rpf, i); + uif = cfg->crc.source == VSP1_DU_CRC_PLANE && + cfg->crc.index == i ? drm_pipe->uif : NULL; + ret = vsp1_du_setup_rpf_pipe(vsp1, pipe, rpf, uif, i); if (ret < 0) dev_err(vsp1->dev, "%s: failed to setup RPF.%u\n", __func__, rpf->entity.index); } + /* Insert and configure the UIF at the BRU output if available. */ + uif = cfg->crc.source == VSP1_DU_CRC_OUTPUT ? drm_pipe->uif : NULL; + ret = vsp1_du_insert_uif(vsp1, pipe, uif, + pipe->bru, pipe->bru->source_pad, + &pipe->output->entity, 0); + if (ret < 0) + dev_err(vsp1->dev, "%s: failed to setup UIF after BRU\n", + __func__); + + /* Disconnect the UIF if it isn't present in the pipeline. */ + if (drm_pipe->uif && cfg->crc.source == VSP1_DU_CRC_NONE) + vsp1_dl_list_write(dl, drm_pipe->uif->route->reg, + VI6_DPR_NODE_UNUSED); + /* Configure all entities in the pipeline. */ list_for_each_entry_safe(entity, next, &pipe->entities, list_pipe) { /* Disconnect unused RPFs from the pipeline. */ @@ -672,6 +766,17 @@ int vsp1_drm_init(struct vsp1_device *vsp1) list_add_tail(&pipe->bru->list_pipe, &pipe->entities); list_add_tail(&pipe->lif->list_pipe, &pipe->entities); list_add_tail(&pipe->output->entity.list_pipe, &pipe->entities); + + /* + * CRC computation is initially disabled, don't add the UIF to + * the pipeline. + */ + if (i < vsp1->info->uif_count) { + drm_pipe->uif = &vsp1->uif[i]->entity; + drm_pipe->uif->sink = &pipe->output->entity; + drm_pipe->uif->sink_pad = 0; + INIT_LIST_HEAD(&drm_pipe->uif->list_pipe); + } } /* Disable all RPFs initially. */ diff --git a/drivers/media/platform/vsp1/vsp1_drm.h b/drivers/media/platform/vsp1/vsp1_drm.h index c6515272da7d..aa07c54e6d9f 100644 --- a/drivers/media/platform/vsp1/vsp1_drm.h +++ b/drivers/media/platform/vsp1/vsp1_drm.h @@ -15,12 +15,17 @@ #include +#include + #include "vsp1_pipe.h" /** * vsp1_drm_pipeline - State for the API exposed to the DRM driver * @pipe: the VSP1 pipeline used for display * @enabled: pipeline state at the beginning of an update + * @uif: UIF entity if available for the pipeline + * @crc.source: source for CRC calculation + * @crc.index: index of the CRC source plane (when crc.source is set to plane) * @du_complete: frame completion callback for the DU driver (optional) * @du_private: data to be passed to the du_complete callback */ @@ -28,6 +33,13 @@ struct vsp1_drm_pipeline { struct vsp1_pipeline pipe; bool enabled; + struct vsp1_entity *uif; + + struct { + enum vsp1_du_crc_source source; + unsigned int index; + } crc; + /* Frame synchronisation */ void (*du_complete)(void *data, bool completed, u32 crc); void *du_private;