From patchwork Tue Jun 12 14:08:11 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Liviu Dudau X-Patchwork-Id: 138354 Delivered-To: patch@linaro.org Received: by 2002:a2e:970d:0:0:0:0:0 with SMTP id r13-v6csp5404389lji; Tue, 12 Jun 2018 07:08:44 -0700 (PDT) X-Google-Smtp-Source: ADUXVKLjiSNr0YA0N2wt8d9EvCFCSI4jfcSz8v2Fj5DiaPfZzrcMIFRjbd1cGVzquUrWA5fsYy/T X-Received: by 2002:a17:902:6847:: with SMTP id f7-v6mr584558pln.173.1528812524651; Tue, 12 Jun 2018 07:08:44 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1528812524; cv=none; d=google.com; s=arc-20160816; b=ZkuNMH0fA1bnXVuAcHeOYSUxCqrVqyYKtUQGOwe1sEJXlzvNCd+i1O+i3QCz0dh2uS ed6QhLPsJTpZx31pv1V+CYX/jzC0lPYrRNM0sMwQFLUd9449Q6BgzgdVTg6ky9sz7FJK JazVm+CtKdQoQoP8tV15CX8dUCwR/f/1UbwEiHQUeINhZ0DDD9K1iUnQ6SOlzxSkxu/8 D/rvHFuF+NYa+zSeMm69HgNlyTnp3rMcrsyDBlD1iMVr0fI0v6O+RsUWpFL+Fy6IW9ua drXjSWWEptVjw4+wN6o1mmi/fL+Q6Woi3fRZN4vpnKOnd3Z28cMpwhTsrB99RdBp+0iW TJsw== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:references:in-reply-to:message-id:date :subject:cc:to:from:arc-authentication-results; bh=KAT1KeP37EBBlPYs300GvTTl8RhnOjWiHrT1iuj9fkU=; b=d9S3a29e7ZAQpbgH9Or96/LFuN31mJD/vJh6IEX97p58MWCF5E7NpYrgCcX9Tiq+iD BhRKEd5xy70Wc2jR9i3DEPjyFuL9q28qWz5LGoxM0LfFQSUT6cW1i9pKrZMbNNEIfYnP 7OWBu1x1VFJ0mItWgHS/yC3nkMLoooS4sy/GLIjUAmyRVVG3qhG9YJTqybENOKE5cOyO nxhGIav/CRPxd0Hx5zxxC8gyqe6LLIqCBf0s9kAxk6QPjcaJ8+0c2uERLe7cyK5IYrq9 nfE/gIo5Q4Ej/XROKRxdm18Ntnp9+nRST7iG9yEnM+8bU1ZpEWKkKBXfcV5SQPIar7H9 Y60g== ARC-Authentication-Results: i=1; mx.google.com; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id i9-v6si200930pgo.36.2018.06.12.07.08.44; Tue, 12 Jun 2018 07:08:44 -0700 (PDT) Received-SPF: pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) client-ip=209.132.180.67; Authentication-Results: mx.google.com; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S934128AbeFLOIm (ORCPT + 30 others); Tue, 12 Jun 2018 10:08:42 -0400 Received: from fw-tnat.cambridge.arm.com ([217.140.96.140]:18863 "EHLO cam-smtp0.cambridge.arm.com" rhost-flags-OK-OK-OK-FAIL) by vger.kernel.org with ESMTP id S934030AbeFLOIi (ORCPT ); Tue, 12 Jun 2018 10:08:38 -0400 Received: from e110455-lin.cambridge.arm.com (e110455-lin.cambridge.arm.com [10.2.131.61]) by cam-smtp0.cambridge.arm.com (8.13.8/8.13.8) with ESMTP id w5CE8DwR031673; Tue, 12 Jun 2018 15:08:18 +0100 From: Liviu Dudau To: Mali DP Maintainers Cc: Gustavo Padovan , Maarten Lankhorst , Sean Paul , DRI-devel , LKML , David Airlie , Brian Starkey , Alexandru-Cosmin Gheorghe , Eric Anholt , Boris Brezillon , Maxime Ripard , Daniel Stone , Liviu Dudau Subject: [PATCH v8 3/5] drm/mali-dp: Add writeback support for DP500. Date: Tue, 12 Jun 2018 15:08:11 +0100 Message-Id: <20180612140813.20419-4-Liviu.Dudau@arm.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20180612140813.20419-1-Liviu.Dudau@arm.com> References: <20180612140813.20419-1-Liviu.Dudau@arm.com> Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Mali DP500 behaves differently from the rest of the Mali DP IP, in that it does not have a one-shot mode and keeps writing the content of the current frame to the provided memory area until stopped. As a way of emulating the one-shot behaviour, we are going to use the CVAL interrupt that is being raised at the start of each frame, during prefetch phase, to act as End-of-Write signal, but with a twist: we are going to disable the memory write engine right after we're notified that it has been enabled, using the knowledge that the bit controlling the enabling will only be acted upon on the next vblank/prefetch. CVAL interrupt will fire durint the next prefetch phase every time the global CVAL bit gets set, so we need a state byte to track the memory write enabling. We also need to pay attention during the disabling of the memory write engine as that requires the CVAL bit to be set in the control register, but we don't want to do that during an atomic commit, as it will write into the hardware a partial state. Signed-off-by: Liviu Dudau --- drivers/gpu/drm/arm/malidp_drv.c | 16 ++++-- drivers/gpu/drm/arm/malidp_drv.h | 4 ++ drivers/gpu/drm/arm/malidp_hw.c | 84 +++++++++++++++++++++++++++++-- drivers/gpu/drm/arm/malidp_hw.h | 5 +- drivers/gpu/drm/arm/malidp_regs.h | 3 +- 5 files changed, 102 insertions(+), 10 deletions(-) -- 2.17.1 diff --git a/drivers/gpu/drm/arm/malidp_drv.c b/drivers/gpu/drm/arm/malidp_drv.c index 8d20faa198cf1..e262620ffed55 100644 --- a/drivers/gpu/drm/arm/malidp_drv.c +++ b/drivers/gpu/drm/arm/malidp_drv.c @@ -170,14 +170,15 @@ static int malidp_set_and_wait_config_valid(struct drm_device *drm) struct malidp_hw_device *hwdev = malidp->dev; int ret; - atomic_set(&malidp->config_valid, 0); hwdev->hw->set_config_valid(hwdev); /* don't wait for config_valid flag if we are in config mode */ - if (hwdev->hw->in_config_mode(hwdev)) + if (hwdev->hw->in_config_mode(hwdev)) { + atomic_set(&malidp->config_valid, MALIDP_CONFIG_VALID_DONE); return 0; + } ret = wait_event_interruptible_timeout(malidp->wq, - atomic_read(&malidp->config_valid) == 1, + atomic_read(&malidp->config_valid) == MALIDP_CONFIG_VALID_DONE, msecs_to_jiffies(MALIDP_CONF_VALID_TIMEOUT)); return (ret > 0) ? 0 : -ETIMEDOUT; @@ -216,12 +217,19 @@ static void malidp_atomic_commit_hw_done(struct drm_atomic_state *state) static void malidp_atomic_commit_tail(struct drm_atomic_state *state) { struct drm_device *drm = state->dev; + struct malidp_drm *malidp = drm->dev_private; struct drm_crtc *crtc; struct drm_crtc_state *old_crtc_state; int i; pm_runtime_get_sync(drm->dev); + /* + * set config_valid to a special value to let IRQ handlers + * know that we are updating registers + */ + atomic_set(&malidp->config_valid, MALIDP_CONFIG_START); + drm_atomic_helper_commit_modeset_disables(drm, state); for_each_old_crtc_in_state(state, crtc, old_crtc_state, i) { @@ -589,7 +597,7 @@ static int malidp_bind(struct device *dev) out_depth = (out_depth << 8) | (output_width[i] & 0xf); malidp_hw_write(hwdev, out_depth, hwdev->hw->map.out_depth_base); - atomic_set(&malidp->config_valid, 0); + atomic_set(&malidp->config_valid, MALIDP_CONFIG_VALID_INIT); init_waitqueue_head(&malidp->wq); ret = malidp_init(drm); diff --git a/drivers/gpu/drm/arm/malidp_drv.h b/drivers/gpu/drm/arm/malidp_drv.h index c70989b933874..e8c41cf1b5bd2 100644 --- a/drivers/gpu/drm/arm/malidp_drv.h +++ b/drivers/gpu/drm/arm/malidp_drv.h @@ -18,6 +18,10 @@ #include #include "malidp_hw.h" +#define MALIDP_CONFIG_VALID_INIT 0 +#define MALIDP_CONFIG_VALID_DONE 1 +#define MALIDP_CONFIG_START 0xd0 + struct malidp_drm { struct malidp_hw_device *dev; struct drm_crtc crtc; diff --git a/drivers/gpu/drm/arm/malidp_hw.c b/drivers/gpu/drm/arm/malidp_hw.c index dd3a15964c588..0524b75f85c6e 100644 --- a/drivers/gpu/drm/arm/malidp_hw.c +++ b/drivers/gpu/drm/arm/malidp_hw.c @@ -22,6 +22,13 @@ #include "malidp_drv.h" #include "malidp_hw.h" +enum { + MW_NOT_ENABLED = 0, /* SE writeback not enabled */ + MW_ONESHOT, /* SE in one-shot mode for writeback */ + MW_START, /* SE started writeback */ + MW_STOP, /* SE finished writeback */ +}; + static const struct malidp_format_id malidp500_de_formats[] = { /* fourcc, layers supporting the format, internal id */ { DRM_FORMAT_ARGB2101010, DE_VIDEO1 | DE_GRAPHICS1 | DE_GRAPHICS2, 0 }, @@ -368,6 +375,51 @@ static long malidp500_se_calc_mclk(struct malidp_hw_device *hwdev, return ret; } +static int malidp500_enable_memwrite(struct malidp_hw_device *hwdev, + dma_addr_t *addrs, s32 *pitches, + int num_planes, u16 w, u16 h, u32 fmt_id) +{ + u32 base = MALIDP500_SE_MEMWRITE_BASE; + u32 de_base = malidp_get_block_base(hwdev, MALIDP_DE_BLOCK); + + /* enable the scaling engine block */ + malidp_hw_setbits(hwdev, MALIDP_SCALE_ENGINE_EN, de_base + MALIDP_DE_DISPLAY_FUNC); + + hwdev->mw_state = MW_START; + + malidp_hw_write(hwdev, fmt_id, base + MALIDP_MW_FORMAT); + switch (num_planes) { + case 2: + malidp_hw_write(hwdev, lower_32_bits(addrs[1]), base + MALIDP_MW_P2_PTR_LOW); + malidp_hw_write(hwdev, upper_32_bits(addrs[1]), base + MALIDP_MW_P2_PTR_HIGH); + malidp_hw_write(hwdev, pitches[1], base + MALIDP_MW_P2_STRIDE); + /* fall through */ + case 1: + malidp_hw_write(hwdev, lower_32_bits(addrs[0]), base + MALIDP_MW_P1_PTR_LOW); + malidp_hw_write(hwdev, upper_32_bits(addrs[0]), base + MALIDP_MW_P1_PTR_HIGH); + malidp_hw_write(hwdev, pitches[0], base + MALIDP_MW_P1_STRIDE); + break; + default: + WARN(1, "Invalid number of planes"); + } + + malidp_hw_write(hwdev, MALIDP_DE_H_ACTIVE(w) | MALIDP_DE_V_ACTIVE(h), + MALIDP500_SE_MEMWRITE_OUT_SIZE); + malidp_hw_setbits(hwdev, MALIDP_SE_MEMWRITE_EN, MALIDP500_SE_CONTROL); + + return 0; +} + +static void malidp500_disable_memwrite(struct malidp_hw_device *hwdev) +{ + u32 base = malidp_get_block_base(hwdev, MALIDP_DE_BLOCK); + + if (hwdev->mw_state == MW_START) + hwdev->mw_state = MW_STOP; + malidp_hw_clearbits(hwdev, MALIDP_SE_MEMWRITE_EN, MALIDP500_SE_CONTROL); + malidp_hw_clearbits(hwdev, MALIDP_SCALE_ENGINE_EN, base + MALIDP_DE_DISPLAY_FUNC); +} + static int malidp550_query_hw(struct malidp_hw_device *hwdev) { u32 conf = malidp_hw_read(hwdev, MALIDP550_CONFIG_ID); @@ -598,6 +650,8 @@ static int malidp550_enable_memwrite(struct malidp_hw_device *hwdev, /* enable the scaling engine block */ malidp_hw_setbits(hwdev, MALIDP_SCALE_ENGINE_EN, de_base + MALIDP_DE_DISPLAY_FUNC); + hwdev->mw_state = MW_ONESHOT; + malidp_hw_write(hwdev, fmt_id, base + MALIDP_MW_FORMAT); switch (num_planes) { case 2: @@ -677,8 +731,9 @@ const struct malidp_hw malidp_device[MALIDP_MAX_DEVICES] = { .vsync_irq = MALIDP500_DE_IRQ_VSYNC, }, .se_irq_map = { - .irq_mask = MALIDP500_SE_IRQ_CONF_MODE, - .vsync_irq = 0, + .irq_mask = MALIDP500_SE_IRQ_CONF_MODE | + MALIDP500_SE_IRQ_CONF_VALID, + .vsync_irq = MALIDP500_SE_IRQ_CONF_VALID, }, .dc_irq_map = { .irq_mask = MALIDP500_DE_IRQ_CONF_VALID, @@ -697,6 +752,8 @@ const struct malidp_hw malidp_device[MALIDP_MAX_DEVICES] = { .rotmem_required = malidp500_rotmem_required, .se_set_scaling_coeffs = malidp500_se_set_scaling_coeffs, .se_calc_mclk = malidp500_se_calc_mclk, + .enable_memwrite = malidp500_enable_memwrite, + .disable_memwrite = malidp500_disable_memwrite, .features = MALIDP_DEVICE_LV_HAS_3_STRIDES, }, [MALIDP_550] = { @@ -841,7 +898,7 @@ static irqreturn_t malidp_de_irq(int irq, void *arg) malidp->event = NULL; spin_unlock(&drm->event_lock); } - atomic_set(&malidp->config_valid, 1); + atomic_set(&malidp->config_valid, MALIDP_CONFIG_VALID_DONE); ret = IRQ_WAKE_THREAD; } @@ -935,7 +992,25 @@ static irqreturn_t malidp_se_irq(int irq, void *arg) mask = malidp_hw_read(hwdev, hw->map.se_base + MALIDP_REG_MASKIRQ); status = malidp_hw_read(hwdev, hw->map.se_base + MALIDP_REG_STATUS); status &= mask; - /* ToDo: status decoding and firing up of VSYNC and page flip events */ + + if (status & se->vsync_irq) { + switch (hwdev->mw_state) { + case MW_STOP: + /* disable writeback after stop */ + hwdev->mw_state = MW_NOT_ENABLED; + break; + case MW_START: + /* writeback started, need to emulate one-shot mode */ + hw->disable_memwrite(hwdev); + /* + * only set config_valid HW bit if there is no + * other update in progress + */ + if (atomic_read(&malidp->config_valid) != MALIDP_CONFIG_START) + hw->set_config_valid(hwdev); + break; + } + } malidp_hw_clear_irq(hwdev, MALIDP_SE_BLOCK, status); @@ -965,6 +1040,7 @@ int malidp_se_irq_init(struct drm_device *drm, int irq) return ret; } + hwdev->mw_state = MW_NOT_ENABLED; malidp_hw_enable_irq(hwdev, MALIDP_SE_BLOCK, hwdev->hw->map.se_irq_map.irq_mask); diff --git a/drivers/gpu/drm/arm/malidp_hw.h b/drivers/gpu/drm/arm/malidp_hw.h index a242e97cf6428..c479738b81af5 100644 --- a/drivers/gpu/drm/arm/malidp_hw.h +++ b/drivers/gpu/drm/arm/malidp_hw.h @@ -178,7 +178,7 @@ struct malidp_hw { long (*se_calc_mclk)(struct malidp_hw_device *hwdev, struct malidp_se_config *se_config, struct videomode *vm); - /** + /* * Enable writing to memory the content of the next frame * @param hwdev - malidp_hw_device structure containing the HW description * @param addrs - array of addresses for each plane @@ -232,6 +232,9 @@ struct malidp_hw_device { /* track the device PM state */ bool pm_suspended; + /* track the SE memory writeback state */ + u8 mw_state; + /* size of memory used for rotating layers, up to two banks available */ u32 rotation_memory[2]; }; diff --git a/drivers/gpu/drm/arm/malidp_regs.h b/drivers/gpu/drm/arm/malidp_regs.h index e2b2c496225e3..93b198f3af864 100644 --- a/drivers/gpu/drm/arm/malidp_regs.h +++ b/drivers/gpu/drm/arm/malidp_regs.h @@ -198,7 +198,8 @@ #define MALIDP500_DE_LG2_PTR_BASE 0x0031c #define MALIDP500_SE_BASE 0x00c00 #define MALIDP500_SE_CONTROL 0x00c0c -#define MALIDP500_SE_PTR_BASE 0x00e0c +#define MALIDP500_SE_MEMWRITE_OUT_SIZE 0x00c2c +#define MALIDP500_SE_MEMWRITE_BASE 0x00e00 #define MALIDP500_DC_IRQ_BASE 0x00f00 #define MALIDP500_CONFIG_VALID 0x00f00 #define MALIDP500_CONFIG_ID 0x00fd4 From patchwork Tue Jun 12 14:08:13 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Liviu Dudau X-Patchwork-Id: 138353 Delivered-To: patch@linaro.org Received: by 2002:a2e:970d:0:0:0:0:0 with SMTP id r13-v6csp5404283lji; Tue, 12 Jun 2018 07:08:40 -0700 (PDT) X-Google-Smtp-Source: ADUXVKKDtNp7JqxXDpRrjMpzfVo9hQrnoJ7d6RvcCtnNvXV1LuT7DlGs4ZdpfEYVlEONHEAA9i58 X-Received: by 2002:a63:9a01:: with SMTP id o1-v6mr433736pge.439.1528812520583; Tue, 12 Jun 2018 07:08:40 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1528812520; cv=none; d=google.com; s=arc-20160816; b=WSz3uHDuFeDJVwi+80LcmCBnU9L8Sq8EeOBywLfV2sEAyglOQFhdrenE6OxL9NugWW q4Yu6c30kNA8Lze79CUBaSLh0qVg9wQEXSjZTTp3obnvDrRI+11sG5wuXaHg7YugAV+a os6oHwz0vCUXPjORW2b+6cuCGqvcg2fEYGmOH1cDxLZ83k/80ss3dsFSs5VRkn7esH67 +6F/Ipi9FCPQ4Pc9wGJg520yBxVxO3Cdr6EdwFj1YJKB2gwqj9QjdT4OdNQt9AwezKp2 m0bVXq0C4d1R5IHztR3O/u9pLY0NiHpN9p404Wb6GP3ITcJpjzwO48aJfTtNjhv5tTz4 UGjA== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:references:in-reply-to:message-id:date :subject:cc:to:from:arc-authentication-results; bh=E3neinC9p3xSHsWgvPsjbMyVYIGs8xrjV39rQluroLo=; b=kA8vG3LizfTU3C0NiNy9UXuUyykjquGRid9UI56Q/z5TZjUxLw0J9hGVTBKfRRrmFB w7nfHQTFk3rG3+IBjj/xWroipjQnSHcY4MTThAvrs6vdRf++Bj9bnx2tq45wiM2jVTMR WBS6yQjRRX5UFku+8IQf12cPazKdqtGaUhfmRPmMgtg9wNyvB7yEIU58yvFRtp8KAke+ saiRifTzJfFuT5f5C7Ncp1iguxJn5s2jUxNY9JkjxEpzolz/D44M5ACfBMML/whX7xfC /qxsSBWacmQpkXfw5nXBr6xEmeABXyChZPEJSSQbYKnMkW0vsMdbgLKPNwbawrtYXXOu pFfA== ARC-Authentication-Results: i=1; mx.google.com; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id i9-v6si200930pgo.36.2018.06.12.07.08.40; Tue, 12 Jun 2018 07:08:40 -0700 (PDT) Received-SPF: pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) client-ip=209.132.180.67; Authentication-Results: mx.google.com; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S934082AbeFLOIh (ORCPT + 30 others); Tue, 12 Jun 2018 10:08:37 -0400 Received: from fw-tnat.cambridge.arm.com ([217.140.96.140]:18859 "EHLO cam-smtp0.cambridge.arm.com" rhost-flags-OK-OK-OK-FAIL) by vger.kernel.org with ESMTP id S933550AbeFLOIe (ORCPT ); Tue, 12 Jun 2018 10:08:34 -0400 Received: from e110455-lin.cambridge.arm.com (e110455-lin.cambridge.arm.com [10.2.131.61]) by cam-smtp0.cambridge.arm.com (8.13.8/8.13.8) with ESMTP id w5CE8DwT031673; Tue, 12 Jun 2018 15:08:18 +0100 From: Liviu Dudau To: Mali DP Maintainers Cc: Gustavo Padovan , Maarten Lankhorst , Sean Paul , DRI-devel , LKML , David Airlie , Brian Starkey , Alexandru-Cosmin Gheorghe , Eric Anholt , Boris Brezillon , Maxime Ripard , Daniel Stone , Mihail Atanassov , Liviu Dudau Subject: [PATCH v8 5/5] drm: mali-dp: Add writeback connector Date: Tue, 12 Jun 2018 15:08:13 +0100 Message-Id: <20180612140813.20419-6-Liviu.Dudau@arm.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20180612140813.20419-1-Liviu.Dudau@arm.com> References: <20180612140813.20419-1-Liviu.Dudau@arm.com> Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org From: Brian Starkey Mali-DP has a memory writeback engine which can be used to write the composition result to a memory buffer. Expose this functionality as a DRM writeback connector on supported hardware. Changes since v1: Daniel Vetter: - Don't require a modeset when writeback routing changes - Make writeback connector always disconnected Changes since v2: - Rebase onto new drm_writeback_connector - Add reset callback, allocating subclassed state Daniel Vetter: - Squash out-fence support into this commit Gustavo Padovan: - Don't signal fence directly from driver (and drop malidp_mw_job) Changes since v3: - Modifications to fit with Mali-DP commit tail changes Signed-off-by: Brian Starkey [rebased and fixed conflicts] Signed-off-by: Mihail Atanassov Signed-off-by: Liviu Dudau --- drivers/gpu/drm/arm/Makefile | 1 + drivers/gpu/drm/arm/malidp_crtc.c | 10 ++ drivers/gpu/drm/arm/malidp_drv.c | 19 ++- drivers/gpu/drm/arm/malidp_drv.h | 3 + drivers/gpu/drm/arm/malidp_hw.c | 5 + drivers/gpu/drm/arm/malidp_mw.c | 250 ++++++++++++++++++++++++++++++ drivers/gpu/drm/arm/malidp_mw.h | 14 ++ drivers/gpu/drm/drm_atomic.c | 4 + 8 files changed, 301 insertions(+), 5 deletions(-) create mode 100644 drivers/gpu/drm/arm/malidp_mw.c create mode 100644 drivers/gpu/drm/arm/malidp_mw.h -- 2.17.1 diff --git a/drivers/gpu/drm/arm/Makefile b/drivers/gpu/drm/arm/Makefile index bb8b158ff90d0..3bf31d1a4722c 100644 --- a/drivers/gpu/drm/arm/Makefile +++ b/drivers/gpu/drm/arm/Makefile @@ -1,4 +1,5 @@ hdlcd-y := hdlcd_drv.o hdlcd_crtc.o obj-$(CONFIG_DRM_HDLCD) += hdlcd.o mali-dp-y := malidp_drv.o malidp_hw.o malidp_planes.o malidp_crtc.o +mali-dp-y += malidp_mw.o obj-$(CONFIG_DRM_MALI_DISPLAY) += mali-dp.o diff --git a/drivers/gpu/drm/arm/malidp_crtc.c b/drivers/gpu/drm/arm/malidp_crtc.c index fcc62bc60f6a7..ef44202fb43f8 100644 --- a/drivers/gpu/drm/arm/malidp_crtc.c +++ b/drivers/gpu/drm/arm/malidp_crtc.c @@ -411,6 +411,16 @@ static int malidp_crtc_atomic_check(struct drm_crtc *crtc, } } + /* If only the writeback routing has changed, we don't need a modeset */ + if (state->connectors_changed) { + u32 old_mask = crtc->state->connector_mask; + u32 new_mask = state->connector_mask; + + if ((old_mask ^ new_mask) == + (1 << drm_connector_index(&malidp->mw_connector.base))) + state->connectors_changed = false; + } + ret = malidp_crtc_atomic_check_gamma(crtc, state); ret = ret ? ret : malidp_crtc_atomic_check_ctm(crtc, state); ret = ret ? ret : malidp_crtc_atomic_check_scaling(crtc, state); diff --git a/drivers/gpu/drm/arm/malidp_drv.c b/drivers/gpu/drm/arm/malidp_drv.c index e262620ffed55..fc264554c5035 100644 --- a/drivers/gpu/drm/arm/malidp_drv.c +++ b/drivers/gpu/drm/arm/malidp_drv.c @@ -31,6 +31,7 @@ #include #include "malidp_drv.h" +#include "malidp_mw.h" #include "malidp_regs.h" #include "malidp_hw.h" @@ -238,7 +239,9 @@ static void malidp_atomic_commit_tail(struct drm_atomic_state *state) malidp_atomic_commit_se_config(crtc, old_crtc_state); } - drm_atomic_helper_commit_planes(drm, state, 0); + drm_atomic_helper_commit_planes(drm, state, DRM_PLANE_COMMIT_ACTIVE_ONLY); + + malidp_mw_atomic_commit(drm, state); drm_atomic_helper_commit_modeset_enables(drm, state); @@ -276,12 +279,18 @@ static int malidp_init(struct drm_device *drm) drm->mode_config.helper_private = &malidp_mode_config_helpers; ret = malidp_crtc_init(drm); - if (ret) { - drm_mode_config_cleanup(drm); - return ret; - } + if (ret) + goto crtc_fail; + + ret = malidp_mw_connector_init(drm); + if (ret) + goto crtc_fail; return 0; + +crtc_fail: + drm_mode_config_cleanup(drm); + return ret; } static void malidp_fini(struct drm_device *drm) diff --git a/drivers/gpu/drm/arm/malidp_drv.h b/drivers/gpu/drm/arm/malidp_drv.h index e8c41cf1b5bd2..5febd4b43e058 100644 --- a/drivers/gpu/drm/arm/malidp_drv.h +++ b/drivers/gpu/drm/arm/malidp_drv.h @@ -13,6 +13,8 @@ #ifndef __MALIDP_DRV_H__ #define __MALIDP_DRV_H__ +#include +#include #include #include #include @@ -25,6 +27,7 @@ struct malidp_drm { struct malidp_hw_device *dev; struct drm_crtc crtc; + struct drm_writeback_connector mw_connector; wait_queue_head_t wq; struct drm_pending_vblank_event *event; atomic_t config_valid; diff --git a/drivers/gpu/drm/arm/malidp_hw.c b/drivers/gpu/drm/arm/malidp_hw.c index df3649203e6a9..e0de7a35a0beb 100644 --- a/drivers/gpu/drm/arm/malidp_hw.c +++ b/drivers/gpu/drm/arm/malidp_hw.c @@ -21,6 +21,7 @@ #include "malidp_drv.h" #include "malidp_hw.h" +#include "malidp_mw.h" enum { MW_NOT_ENABLED = 0, /* SE writeback not enabled */ @@ -995,7 +996,11 @@ static irqreturn_t malidp_se_irq(int irq, void *arg) if (status & se->vsync_irq) { switch (hwdev->mw_state) { + case MW_ONESHOT: + drm_writeback_signal_completion(&malidp->mw_connector, 0); + break; case MW_STOP: + drm_writeback_signal_completion(&malidp->mw_connector, 0); /* disable writeback after stop */ hwdev->mw_state = MW_NOT_ENABLED; break; diff --git a/drivers/gpu/drm/arm/malidp_mw.c b/drivers/gpu/drm/arm/malidp_mw.c new file mode 100644 index 0000000000000..cfd718e7e97c1 --- /dev/null +++ b/drivers/gpu/drm/arm/malidp_mw.c @@ -0,0 +1,250 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * (C) COPYRIGHT 2016 ARM Limited. All rights reserved. + * Author: Brian Starkey + * + * ARM Mali DP Writeback connector implementation + */ +#include +#include +#include +#include +#include +#include +#include +#include + +#include "malidp_drv.h" +#include "malidp_hw.h" +#include "malidp_mw.h" + +#define to_mw_state(_state) (struct malidp_mw_connector_state *)(_state) + +struct malidp_mw_connector_state { + struct drm_connector_state base; + dma_addr_t addrs[2]; + s32 pitches[2]; + u8 format; + u8 n_planes; +}; + +static int malidp_mw_connector_get_modes(struct drm_connector *connector) +{ + struct drm_device *dev = connector->dev; + + return drm_add_modes_noedid(connector, dev->mode_config.max_width, + dev->mode_config.max_height); +} + +static enum drm_mode_status +malidp_mw_connector_mode_valid(struct drm_connector *connector, + struct drm_display_mode *mode) +{ + struct drm_device *dev = connector->dev; + struct drm_mode_config *mode_config = &dev->mode_config; + int w = mode->hdisplay, h = mode->vdisplay; + + if ((w < mode_config->min_width) || (w > mode_config->max_width)) + return MODE_BAD_HVALUE; + + if ((h < mode_config->min_height) || (h > mode_config->max_height)) + return MODE_BAD_VVALUE; + + return MODE_OK; +} + +const struct drm_connector_helper_funcs malidp_mw_connector_helper_funcs = { + .get_modes = malidp_mw_connector_get_modes, + .mode_valid = malidp_mw_connector_mode_valid, +}; + +static void malidp_mw_connector_reset(struct drm_connector *connector) +{ + struct malidp_mw_connector_state *mw_state = + kzalloc(sizeof(*mw_state), GFP_KERNEL); + + if (connector->state) + __drm_atomic_helper_connector_destroy_state(connector->state); + + kfree(connector->state); + __drm_atomic_helper_connector_reset(connector, &mw_state->base); +} + +static enum drm_connector_status +malidp_mw_connector_detect(struct drm_connector *connector, bool force) +{ + return connector_status_disconnected; +} + +static void malidp_mw_connector_destroy(struct drm_connector *connector) +{ + drm_connector_cleanup(connector); +} + +static struct drm_connector_state * +malidp_mw_connector_duplicate_state(struct drm_connector *connector) +{ + struct malidp_mw_connector_state *mw_state; + + if (WARN_ON(!connector->state)) + return NULL; + + mw_state = kzalloc(sizeof(*mw_state), GFP_KERNEL); + if (!mw_state) + return NULL; + + /* No need to preserve any of our driver-local data */ + __drm_atomic_helper_connector_duplicate_state(connector, &mw_state->base); + + return &mw_state->base; +} + +static const struct drm_connector_funcs malidp_mw_connector_funcs = { + .reset = malidp_mw_connector_reset, + .detect = malidp_mw_connector_detect, + .fill_modes = drm_helper_probe_single_connector_modes, + .destroy = malidp_mw_connector_destroy, + .atomic_duplicate_state = malidp_mw_connector_duplicate_state, + .atomic_destroy_state = drm_atomic_helper_connector_destroy_state, +}; + +static int +malidp_mw_encoder_atomic_check(struct drm_encoder *encoder, + struct drm_crtc_state *crtc_state, + struct drm_connector_state *conn_state) +{ + struct malidp_mw_connector_state *mw_state = to_mw_state(conn_state); + struct malidp_drm *malidp = encoder->dev->dev_private; + struct drm_framebuffer *fb; + int i, n_planes; + + if (!conn_state->writeback_job || !conn_state->writeback_job->fb) + return 0; + + fb = conn_state->writeback_job->fb; + if ((fb->width != crtc_state->mode.hdisplay) || + (fb->height != crtc_state->mode.vdisplay)) { + DRM_DEBUG_KMS("Invalid framebuffer size %ux%u\n", + fb->width, fb->height); + return -EINVAL; + } + + mw_state->format = + malidp_hw_get_format_id(&malidp->dev->hw->map, SE_MEMWRITE, + fb->format->format); + if (mw_state->format == MALIDP_INVALID_FORMAT_ID) { + struct drm_format_name_buf format_name; + + DRM_DEBUG_KMS("Invalid pixel format %s\n", + drm_get_format_name(fb->format->format, + &format_name)); + return -EINVAL; + } + + n_planes = drm_format_num_planes(fb->format->format); + for (i = 0; i < n_planes; i++) { + struct drm_gem_cma_object *obj = drm_fb_cma_get_gem_obj(fb, i); + /* memory write buffers are never rotated */ + u8 alignment = malidp_hw_get_pitch_align(malidp->dev, 0); + + if (fb->pitches[i] & (alignment - 1)) { + DRM_DEBUG_KMS("Invalid pitch %u for plane %d\n", + fb->pitches[i], i); + return -EINVAL; + } + mw_state->pitches[i] = fb->pitches[i]; + mw_state->addrs[i] = obj->paddr + fb->offsets[i]; + } + mw_state->n_planes = n_planes; + + return 0; +} + +static const struct drm_encoder_helper_funcs malidp_mw_encoder_helper_funcs = { + .atomic_check = malidp_mw_encoder_atomic_check, +}; + +static u32 *get_writeback_formats(struct malidp_drm *malidp, int *n_formats) +{ + const struct malidp_hw_regmap *map = &malidp->dev->hw->map; + u32 *formats; + int n, i; + + formats = kcalloc(map->n_pixel_formats, sizeof(*formats), + GFP_KERNEL); + if (!formats) + return NULL; + + for (n = 0, i = 0; i < map->n_pixel_formats; i++) { + if (map->pixel_formats[i].layer & SE_MEMWRITE) + formats[n++] = map->pixel_formats[i].format; + } + + *n_formats = n; + + return formats; +} + +int malidp_mw_connector_init(struct drm_device *drm) +{ + struct malidp_drm *malidp = drm->dev_private; + u32 *formats; + int ret, n_formats; + + if (!malidp->dev->hw->enable_memwrite) + return 0; + + malidp->mw_connector.encoder.possible_crtcs = 1 << drm_crtc_index(&malidp->crtc); + drm_connector_helper_add(&malidp->mw_connector.base, + &malidp_mw_connector_helper_funcs); + + formats = get_writeback_formats(malidp, &n_formats); + if (!formats) + return -ENOMEM; + + ret = drm_writeback_connector_init(drm, &malidp->mw_connector, + &malidp_mw_connector_funcs, + &malidp_mw_encoder_helper_funcs, + formats, n_formats); + kfree(formats); + if (ret) + return ret; + + return 0; +} + +void malidp_mw_atomic_commit(struct drm_device *drm, + struct drm_atomic_state *old_state) +{ + struct malidp_drm *malidp = drm->dev_private; + struct drm_writeback_connector *mw_conn = &malidp->mw_connector; + struct drm_connector_state *conn_state = mw_conn->base.state; + struct malidp_hw_device *hwdev = malidp->dev; + struct malidp_mw_connector_state *mw_state; + + if (!conn_state) + return; + + mw_state = to_mw_state(conn_state); + + if (conn_state->writeback_job && conn_state->writeback_job->fb) { + struct drm_framebuffer *fb = conn_state->writeback_job->fb; + + DRM_DEV_DEBUG_DRIVER(drm->dev, + "Enable memwrite %ux%u:%d %pad fmt: %u\n", + fb->width, fb->height, + mw_state->pitches[0], + &mw_state->addrs[0], + mw_state->format); + + drm_writeback_queue_job(mw_conn, conn_state->writeback_job); + conn_state->writeback_job = NULL; + + hwdev->hw->enable_memwrite(hwdev, mw_state->addrs, + mw_state->pitches, mw_state->n_planes, + fb->width, fb->height, mw_state->format); + } else { + DRM_DEV_DEBUG_DRIVER(drm->dev, "Disable memwrite\n"); + hwdev->hw->disable_memwrite(hwdev); + } +} diff --git a/drivers/gpu/drm/arm/malidp_mw.h b/drivers/gpu/drm/arm/malidp_mw.h new file mode 100644 index 0000000000000..19a007676a1db --- /dev/null +++ b/drivers/gpu/drm/arm/malidp_mw.h @@ -0,0 +1,14 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * (C) COPYRIGHT 2016 ARM Limited. All rights reserved. + * Author: Brian Starkey + * + */ + +#ifndef __MALIDP_MW_H__ +#define __MALIDP_MW_H__ + +int malidp_mw_connector_init(struct drm_device *drm); +void malidp_mw_atomic_commit(struct drm_device *drm, + struct drm_atomic_state *old_state); +#endif diff --git a/drivers/gpu/drm/drm_atomic.c b/drivers/gpu/drm/drm_atomic.c index db3cb47da31b6..da80ca611d918 100644 --- a/drivers/gpu/drm/drm_atomic.c +++ b/drivers/gpu/drm/drm_atomic.c @@ -1390,6 +1390,10 @@ static void drm_atomic_connector_print_state(struct drm_printer *p, drm_printf(p, "connector[%u]: %s\n", connector->base.id, connector->name); drm_printf(p, "\tcrtc=%s\n", state->crtc ? state->crtc->name : "(null)"); + if (connector->connector_type == DRM_MODE_CONNECTOR_WRITEBACK) + if (state->writeback_job && state->writeback_job->fb) + drm_printf(p, "\tfb=%d\n", state->writeback_job->fb->base.id); + if (connector->funcs->atomic_print_state) connector->funcs->atomic_print_state(p, state); }