From 946485d0ede5bb29d3aad55bf7afd35cee1ef529 Mon Sep 17 00:00:00 2001 From: Fabio Estevam Date: Fri, 28 Sep 2018 16:13:25 -0300 Subject: drm/imx: Switch to SPDX identifier Adopt the SPDX license identifier headers to ease license compliance management. Signed-off-by: Fabio Estevam Signed-off-by: Philipp Zabel --- drivers/gpu/drm/imx/dw_hdmi-imx.c | 5 +---- drivers/gpu/drm/imx/imx-drm-core.c | 11 +---------- drivers/gpu/drm/imx/imx-ldb.c | 10 +--------- drivers/gpu/drm/imx/imx-tve.c | 10 +--------- drivers/gpu/drm/imx/ipuv3-crtc.c | 10 +--------- drivers/gpu/drm/imx/ipuv3-plane.c | 10 +--------- drivers/gpu/drm/imx/parallel-display.c | 10 +--------- 7 files changed, 7 insertions(+), 59 deletions(-) (limited to 'drivers/gpu/drm') diff --git a/drivers/gpu/drm/imx/dw_hdmi-imx.c b/drivers/gpu/drm/imx/dw_hdmi-imx.c index fe6becdcc29e..77a26fd3a44a 100644 --- a/drivers/gpu/drm/imx/dw_hdmi-imx.c +++ b/drivers/gpu/drm/imx/dw_hdmi-imx.c @@ -1,10 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0 /* Copyright (C) 2011-2013 Freescale Semiconductor, Inc. * * derived from imx-hdmi.c(renamed to bridge/dw_hdmi.c now) - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include #include diff --git a/drivers/gpu/drm/imx/imx-drm-core.c b/drivers/gpu/drm/imx/imx-drm-core.c index 0e6942f21a4e..820c7e3878f0 100644 --- a/drivers/gpu/drm/imx/imx-drm-core.c +++ b/drivers/gpu/drm/imx/imx-drm-core.c @@ -1,17 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0+ /* * Freescale i.MX drm driver * * Copyright (C) 2011 Sascha Hauer, Pengutronix - * - * 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. - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * */ #include #include diff --git a/drivers/gpu/drm/imx/imx-ldb.c b/drivers/gpu/drm/imx/imx-ldb.c index 3bd0f8a18e74..2c5bbe317353 100644 --- a/drivers/gpu/drm/imx/imx-ldb.c +++ b/drivers/gpu/drm/imx/imx-ldb.c @@ -1,16 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0+ /* * i.MX drm driver - LVDS display bridge * * Copyright (C) 2012 Sascha Hauer, Pengutronix - * - * 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. - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. */ #include diff --git a/drivers/gpu/drm/imx/imx-tve.c b/drivers/gpu/drm/imx/imx-tve.c index cffd3310240e..4bc3ead5c4e3 100644 --- a/drivers/gpu/drm/imx/imx-tve.c +++ b/drivers/gpu/drm/imx/imx-tve.c @@ -1,16 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0+ /* * i.MX drm driver - Television Encoder (TVEv2) * * Copyright (C) 2013 Philipp Zabel, Pengutronix - * - * 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. - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. */ #include diff --git a/drivers/gpu/drm/imx/ipuv3-crtc.c b/drivers/gpu/drm/imx/ipuv3-crtc.c index 7d4b710b837a..058b53c0aa7e 100644 --- a/drivers/gpu/drm/imx/ipuv3-crtc.c +++ b/drivers/gpu/drm/imx/ipuv3-crtc.c @@ -1,16 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0+ /* * i.MX IPUv3 Graphics driver * * Copyright (C) 2011 Sascha Hauer, Pengutronix - * - * 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. - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. */ #include #include diff --git a/drivers/gpu/drm/imx/ipuv3-plane.c b/drivers/gpu/drm/imx/ipuv3-plane.c index 40605fdf0e33..9db833b68813 100644 --- a/drivers/gpu/drm/imx/ipuv3-plane.c +++ b/drivers/gpu/drm/imx/ipuv3-plane.c @@ -1,16 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0+ /* * i.MX IPUv3 DP Overlay Planes * * Copyright (C) 2013 Philipp Zabel, Pengutronix - * - * 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. - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. */ #include diff --git a/drivers/gpu/drm/imx/parallel-display.c b/drivers/gpu/drm/imx/parallel-display.c index aefd04e18f93..f3ce51121dd6 100644 --- a/drivers/gpu/drm/imx/parallel-display.c +++ b/drivers/gpu/drm/imx/parallel-display.c @@ -1,16 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0+ /* * i.MX drm driver - parallel display implementation * * Copyright (C) 2012 Sascha Hauer, Pengutronix - * - * 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. - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. */ #include -- cgit v1.2.3 From fac8033fe3abbfd9b4404bf803e00a370277470a Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Sat, 27 Oct 2018 07:47:41 +0200 Subject: drm/imx: imx-tve: constify clk_ops structure The clk_ops structure is only stored in the ops field of a clk_init_data structure. This field is const, so the clk_ops structure can be const as well. Identified and transformed using Coccinelle. Signed-off-by: Julia Lawall Signed-off-by: Philipp Zabel --- drivers/gpu/drm/imx/imx-tve.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/gpu/drm') diff --git a/drivers/gpu/drm/imx/imx-tve.c b/drivers/gpu/drm/imx/imx-tve.c index 4bc3ead5c4e3..293dd5752583 100644 --- a/drivers/gpu/drm/imx/imx-tve.c +++ b/drivers/gpu/drm/imx/imx-tve.c @@ -434,7 +434,7 @@ static int clk_tve_di_set_rate(struct clk_hw *hw, unsigned long rate, return 0; } -static struct clk_ops clk_tve_di_ops = { +static const struct clk_ops clk_tve_di_ops = { .round_rate = clk_tve_di_round_rate, .set_rate = clk_tve_di_set_rate, .recalc_rate = clk_tve_di_recalc_rate, -- cgit v1.2.3 From 97c78f4d07e5033717c08b650462b3087ecfe8e8 Mon Sep 17 00:00:00 2001 From: Philipp Zabel Date: Fri, 24 Feb 2017 18:38:08 +0100 Subject: drm/imx: ipuv3-plane: add IDMAC timeout warning ipu_plane_disable should never be called while the plane IDMAC channel is active. The busy wait is just a safety net that should never time out. Signed-off-by: Philipp Zabel --- drivers/gpu/drm/imx/ipuv3-plane.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) (limited to 'drivers/gpu/drm') diff --git a/drivers/gpu/drm/imx/ipuv3-plane.c b/drivers/gpu/drm/imx/ipuv3-plane.c index 9db833b68813..c390924de93d 100644 --- a/drivers/gpu/drm/imx/ipuv3-plane.c +++ b/drivers/gpu/drm/imx/ipuv3-plane.c @@ -228,9 +228,15 @@ static void ipu_plane_enable(struct ipu_plane *ipu_plane) void ipu_plane_disable(struct ipu_plane *ipu_plane, bool disable_dp_channel) { + int ret; + DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__); - ipu_idmac_wait_busy(ipu_plane->ipu_ch, 50); + ret = ipu_idmac_wait_busy(ipu_plane->ipu_ch, 50); + if (ret == -ETIMEDOUT) { + DRM_ERROR("[PLANE:%d] IDMAC timeout\n", + ipu_plane->base.base.id); + } if (ipu_plane->dp && disable_dp_channel) ipu_dp_disable_channel(ipu_plane->dp, false); -- cgit v1.2.3 From f4163814813fb3f3f6f2fd791429bd41135f1f79 Mon Sep 17 00:00:00 2001 From: Lucas Stach Date: Mon, 5 Nov 2018 18:12:38 +0100 Subject: drm/etnaviv: kill active fence tracking There is no need to track the currently active fence. The GPU scheduler keeps track of all the in-flight jobs. Signed-off-by: Lucas Stach Reviewed-by: Philipp Zabel --- drivers/gpu/drm/etnaviv/etnaviv_gpu.c | 7 ++----- drivers/gpu/drm/etnaviv/etnaviv_gpu.h | 1 - 2 files changed, 2 insertions(+), 6 deletions(-) (limited to 'drivers/gpu/drm') diff --git a/drivers/gpu/drm/etnaviv/etnaviv_gpu.c b/drivers/gpu/drm/etnaviv/etnaviv_gpu.c index f225fbc6edd2..e48d9ebf08bc 100644 --- a/drivers/gpu/drm/etnaviv/etnaviv_gpu.c +++ b/drivers/gpu/drm/etnaviv/etnaviv_gpu.c @@ -994,7 +994,6 @@ void etnaviv_gpu_recover_hang(struct etnaviv_gpu *gpu) complete(&gpu->event_free); bitmap_zero(gpu->event_bitmap, ETNA_NR_EVENTS); spin_unlock_irqrestore(&gpu->event_spinlock, flags); - gpu->completed_fence = gpu->active_fence; etnaviv_gpu_hw_init(gpu); gpu->lastctx = NULL; @@ -1306,8 +1305,6 @@ struct dma_fence *etnaviv_gpu_submit(struct etnaviv_gem_submit *submit) goto out_unlock; } - gpu->active_fence = gpu_fence->seqno; - if (submit->nr_pmrs) { gpu->event[event[1]].sync_point = &sync_point_perfmon_sample_pre; kref_get(&submit->refcount); @@ -1806,8 +1803,8 @@ static int etnaviv_gpu_rpm_suspend(struct device *dev) struct etnaviv_gpu *gpu = dev_get_drvdata(dev); u32 idle, mask; - /* If we have outstanding fences, we're not idle */ - if (gpu->completed_fence != gpu->active_fence) + /* If there are any jobs in the HW queue, we're not idle */ + if (atomic_read(&gpu->sched.hw_rq_count)) return -EBUSY; /* Check whether the hardware (except FE) is idle */ diff --git a/drivers/gpu/drm/etnaviv/etnaviv_gpu.h b/drivers/gpu/drm/etnaviv/etnaviv_gpu.h index 9a75a6937268..abea0c34675c 100644 --- a/drivers/gpu/drm/etnaviv/etnaviv_gpu.h +++ b/drivers/gpu/drm/etnaviv/etnaviv_gpu.h @@ -121,7 +121,6 @@ struct etnaviv_gpu { struct mutex fence_lock; struct idr fence_idr; u32 next_fence; - u32 active_fence; u32 completed_fence; wait_queue_head_t fence_event; u64 fence_context; -- cgit v1.2.3 From 3283ee771c88bdf28d427b7ff0831a13213a812c Mon Sep 17 00:00:00 2001 From: Lucas Stach Date: Mon, 5 Nov 2018 18:12:39 +0100 Subject: drm/etnaviv: consolidate hardware fence handling in etnaviv_gpu This is the only place in the driver that should have to deal with the raw hardware fences. To avoid any further confusion, consolidate the fence handling in this file and remove any traces of this from the header files. Signed-off-by: Lucas Stach Reviewed-by: Philipp Zabel --- drivers/gpu/drm/etnaviv/etnaviv_drv.h | 11 ----------- drivers/gpu/drm/etnaviv/etnaviv_gpu.c | 8 +++++++- drivers/gpu/drm/etnaviv/etnaviv_gpu.h | 5 ----- 3 files changed, 7 insertions(+), 17 deletions(-) (limited to 'drivers/gpu/drm') diff --git a/drivers/gpu/drm/etnaviv/etnaviv_drv.h b/drivers/gpu/drm/etnaviv/etnaviv_drv.h index 8d02d1b7dcf5..4bf698de5996 100644 --- a/drivers/gpu/drm/etnaviv/etnaviv_drv.h +++ b/drivers/gpu/drm/etnaviv/etnaviv_drv.h @@ -107,17 +107,6 @@ static inline size_t size_vstruct(size_t nelem, size_t elem_size, size_t base) return base + nelem * elem_size; } -/* returns true if fence a comes after fence b */ -static inline bool fence_after(u32 a, u32 b) -{ - return (s32)(a - b) > 0; -} - -static inline bool fence_after_eq(u32 a, u32 b) -{ - return (s32)(a - b) >= 0; -} - /* * Etnaviv timeouts are specified wrt CLOCK_MONOTONIC, not jiffies. * We need to calculate the timeout in terms of number of jiffies diff --git a/drivers/gpu/drm/etnaviv/etnaviv_gpu.c b/drivers/gpu/drm/etnaviv/etnaviv_gpu.c index e48d9ebf08bc..8fbe77cae810 100644 --- a/drivers/gpu/drm/etnaviv/etnaviv_gpu.c +++ b/drivers/gpu/drm/etnaviv/etnaviv_gpu.c @@ -1031,7 +1031,7 @@ static bool etnaviv_fence_signaled(struct dma_fence *fence) { struct etnaviv_fence *f = to_etnaviv_fence(fence); - return fence_completed(f->gpu, f->base.seqno); + return (s32)(f->gpu->completed_fence - f->base.seqno) >= 0; } static void etnaviv_fence_release(struct dma_fence *fence) @@ -1070,6 +1070,12 @@ static struct dma_fence *etnaviv_gpu_fence_alloc(struct etnaviv_gpu *gpu) return &f->base; } +/* returns true if fence a comes after fence b */ +static inline bool fence_after(u32 a, u32 b) +{ + return (s32)(a - b) > 0; +} + /* * event management: */ diff --git a/drivers/gpu/drm/etnaviv/etnaviv_gpu.h b/drivers/gpu/drm/etnaviv/etnaviv_gpu.h index abea0c34675c..74758f21e5d3 100644 --- a/drivers/gpu/drm/etnaviv/etnaviv_gpu.h +++ b/drivers/gpu/drm/etnaviv/etnaviv_gpu.h @@ -160,11 +160,6 @@ static inline u32 gpu_read(struct etnaviv_gpu *gpu, u32 reg) return readl(gpu->mmio + reg); } -static inline bool fence_completed(struct etnaviv_gpu *gpu, u32 fence) -{ - return fence_after_eq(gpu->completed_fence, fence); -} - int etnaviv_gpu_get_param(struct etnaviv_gpu *gpu, u32 param, u64 *value); int etnaviv_gpu_init(struct etnaviv_gpu *gpu); -- cgit v1.2.3 From 99e294492ef9eb7edaf92b1280377abd07f99c40 Mon Sep 17 00:00:00 2001 From: Thomas Zimmermann Date: Wed, 26 Sep 2018 13:41:39 +0200 Subject: drm/etnaviv: Replace drm_dev_unref with drm_dev_put This patch unifies the naming of DRM functions for reference counting of struct drm_device. The resulting code is more aligned with the rest of the Linux kernel interfaces. Signed-off-by: Thomas Zimmermann Signed-off-by: Lucas Stach --- drivers/gpu/drm/etnaviv/etnaviv_drv.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers/gpu/drm') diff --git a/drivers/gpu/drm/etnaviv/etnaviv_drv.c b/drivers/gpu/drm/etnaviv/etnaviv_drv.c index 83c1f46670bf..1bb1d09e5fb0 100644 --- a/drivers/gpu/drm/etnaviv/etnaviv_drv.c +++ b/drivers/gpu/drm/etnaviv/etnaviv_drv.c @@ -523,7 +523,7 @@ static int etnaviv_bind(struct device *dev) if (!priv) { dev_err(dev, "failed to allocate private data\n"); ret = -ENOMEM; - goto out_unref; + goto out_put; } drm->dev_private = priv; @@ -549,8 +549,8 @@ out_register: component_unbind_all(dev, drm); out_bind: kfree(priv); -out_unref: - drm_dev_unref(drm); +out_put: + drm_dev_put(drm); return ret; } @@ -567,7 +567,7 @@ static void etnaviv_unbind(struct device *dev) drm->dev_private = NULL; kfree(priv); - drm_dev_unref(drm); + drm_dev_put(drm); } static const struct component_master_ops etnaviv_master_ops = { -- cgit v1.2.3 From 534903d60376b4989b76ec445630aa10f2bc3043 Mon Sep 17 00:00:00 2001 From: Ville Syrjälä Date: Thu, 1 Nov 2018 20:46:44 +0200 Subject: drm/atomic: Use explicit old crtc state in drm_atomic_add_affected_planes() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Replace 'crtc->state' with the explicit old crtc state. Actually it shouldn't matter whether we use the old or the new crtc state here since any plane that has been removed from the crtc since the crtc state was duplicated will have been added to the atomic state already. That is, you can't call drm_atomic_set_crtc_for_plane() without having the new plane state already in hand. Signed-off-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20181101184646.14753-1-ville.syrjala@linux.intel.com Reviewed-by: Daniel Vetter Acked-by: Harry Wentland --- drivers/gpu/drm/drm_atomic.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'drivers/gpu/drm') diff --git a/drivers/gpu/drm/drm_atomic.c b/drivers/gpu/drm/drm_atomic.c index 2870ae205237..fca22998b75b 100644 --- a/drivers/gpu/drm/drm_atomic.c +++ b/drivers/gpu/drm/drm_atomic.c @@ -922,6 +922,8 @@ int drm_atomic_add_affected_planes(struct drm_atomic_state *state, struct drm_crtc *crtc) { + const struct drm_crtc_state *old_crtc_state = + drm_atomic_get_old_crtc_state(state, crtc); struct drm_plane *plane; WARN_ON(!drm_atomic_get_new_crtc_state(state, crtc)); @@ -929,7 +931,7 @@ drm_atomic_add_affected_planes(struct drm_atomic_state *state, DRM_DEBUG_ATOMIC("Adding all current planes for [CRTC:%d:%s] to %p\n", crtc->base.id, crtc->name, state); - drm_for_each_plane_mask(plane, state->dev, crtc->state->plane_mask) { + drm_for_each_plane_mask(plane, state->dev, old_crtc_state->plane_mask) { struct drm_plane_state *plane_state = drm_atomic_get_plane_state(state, plane); -- cgit v1.2.3 From b2432adf33e8c8eb81afaba3030f0ba0145ce7d4 Mon Sep 17 00:00:00 2001 From: Ville Syrjälä Date: Thu, 1 Nov 2018 20:46:45 +0200 Subject: drm/atomic: Use explicit old/new state in drm_atomic_crtc_check() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Convert drm_atomic_crtc_check() over to using explicit old vs. new crtc states. Avoids the confusion of "what does crtc->state mean again?". Signed-off-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20181101184646.14753-2-ville.syrjala@linux.intel.com Reviewed-by: Daniel Vetter --- drivers/gpu/drm/drm_atomic.c | 26 +++++++++++++++----------- 1 file changed, 15 insertions(+), 11 deletions(-) (limited to 'drivers/gpu/drm') diff --git a/drivers/gpu/drm/drm_atomic.c b/drivers/gpu/drm/drm_atomic.c index fca22998b75b..4e961b03f161 100644 --- a/drivers/gpu/drm/drm_atomic.c +++ b/drivers/gpu/drm/drm_atomic.c @@ -310,9 +310,11 @@ drm_atomic_get_crtc_state(struct drm_atomic_state *state, } EXPORT_SYMBOL(drm_atomic_get_crtc_state); -static int drm_atomic_crtc_check(struct drm_crtc *crtc, - struct drm_crtc_state *state) +static int drm_atomic_crtc_check(const struct drm_crtc_state *old_crtc_state, + const struct drm_crtc_state *new_crtc_state) { + struct drm_crtc *crtc = new_crtc_state->crtc; + /* NOTE: we explicitly don't enforce constraints such as primary * layer covering entire screen, since that is something we want * to allow (on hw that supports it). For hw that does not, it @@ -321,7 +323,7 @@ static int drm_atomic_crtc_check(struct drm_crtc *crtc, * TODO: Add generic modeset state checks once we support those. */ - if (state->active && !state->enable) { + if (new_crtc_state->active && !new_crtc_state->enable) { DRM_DEBUG_ATOMIC("[CRTC:%d:%s] active without enabled\n", crtc->base.id, crtc->name); return -EINVAL; @@ -331,14 +333,14 @@ static int drm_atomic_crtc_check(struct drm_crtc *crtc, * as this is a kernel-internal detail that userspace should never * be able to trigger. */ if (drm_core_check_feature(crtc->dev, DRIVER_ATOMIC) && - WARN_ON(state->enable && !state->mode_blob)) { + WARN_ON(new_crtc_state->enable && !new_crtc_state->mode_blob)) { DRM_DEBUG_ATOMIC("[CRTC:%d:%s] enabled without mode blob\n", crtc->base.id, crtc->name); return -EINVAL; } if (drm_core_check_feature(crtc->dev, DRIVER_ATOMIC) && - WARN_ON(!state->enable && state->mode_blob)) { + WARN_ON(!new_crtc_state->enable && new_crtc_state->mode_blob)) { DRM_DEBUG_ATOMIC("[CRTC:%d:%s] disabled with mode blob\n", crtc->base.id, crtc->name); return -EINVAL; @@ -354,7 +356,8 @@ static int drm_atomic_crtc_check(struct drm_crtc *crtc, * and legacy page_flip IOCTL which also reject service on a disabled * pipe. */ - if (state->event && !state->active && !crtc->state->active) { + if (new_crtc_state->event && + !new_crtc_state->active && !old_crtc_state->active) { DRM_DEBUG_ATOMIC("[CRTC:%d:%s] requesting event but off\n", crtc->base.id, crtc->name); return -EINVAL; @@ -960,7 +963,8 @@ int drm_atomic_check_only(struct drm_atomic_state *state) struct drm_plane *plane; struct drm_plane_state *plane_state; struct drm_crtc *crtc; - struct drm_crtc_state *crtc_state; + struct drm_crtc_state *old_crtc_state; + struct drm_crtc_state *new_crtc_state; struct drm_connector *conn; struct drm_connector_state *conn_state; int i, ret = 0; @@ -976,8 +980,8 @@ int drm_atomic_check_only(struct drm_atomic_state *state) } } - for_each_new_crtc_in_state(state, crtc, crtc_state, i) { - ret = drm_atomic_crtc_check(crtc, crtc_state); + for_each_oldnew_crtc_in_state(state, crtc, old_crtc_state, new_crtc_state, i) { + ret = drm_atomic_crtc_check(old_crtc_state, new_crtc_state); if (ret) { DRM_DEBUG_ATOMIC("[CRTC:%d:%s] atomic core check failed\n", crtc->base.id, crtc->name); @@ -1005,8 +1009,8 @@ int drm_atomic_check_only(struct drm_atomic_state *state) } if (!state->allow_modeset) { - for_each_new_crtc_in_state(state, crtc, crtc_state, i) { - if (drm_atomic_crtc_needs_modeset(crtc_state)) { + for_each_new_crtc_in_state(state, crtc, new_crtc_state, i) { + if (drm_atomic_crtc_needs_modeset(new_crtc_state)) { DRM_DEBUG_ATOMIC("[CRTC:%d:%s] requires full modeset\n", crtc->base.id, crtc->name); return -EINVAL; -- cgit v1.2.3 From d9be05b784225e68cf0c9b95180d3081b4663745 Mon Sep 17 00:00:00 2001 From: Ville Syrjälä Date: Tue, 6 Nov 2018 21:16:24 +0200 Subject: drm/atomic: Use explicit old/new state in drm_atomic_plane_check() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Convert drm_atomic_plane_check() over to using explicit old vs. new plane states. Avoids the confusion of "what does plane->state mean again?". v2: Stick to the multi-stage logic in plane_switching_crtc() (Daniel) Signed-off-by: Ville Syrjälä Reviewed-by: Daniel Vetter Link: https://patchwork.freedesktop.org/patch/msgid/20181106191624.2207-1-ville.syrjala@linux.intel.com --- drivers/gpu/drm/drm_atomic.c | 85 ++++++++++++++++++++++++-------------------- 1 file changed, 46 insertions(+), 39 deletions(-) (limited to 'drivers/gpu/drm') diff --git a/drivers/gpu/drm/drm_atomic.c b/drivers/gpu/drm/drm_atomic.c index 4e961b03f161..a16dc34b62c5 100644 --- a/drivers/gpu/drm/drm_atomic.c +++ b/drivers/gpu/drm/drm_atomic.c @@ -487,14 +487,13 @@ drm_atomic_get_plane_state(struct drm_atomic_state *state, EXPORT_SYMBOL(drm_atomic_get_plane_state); static bool -plane_switching_crtc(struct drm_atomic_state *state, - struct drm_plane *plane, - struct drm_plane_state *plane_state) +plane_switching_crtc(const struct drm_plane_state *old_plane_state, + const struct drm_plane_state *new_plane_state) { - if (!plane->state->crtc || !plane_state->crtc) + if (!old_plane_state->crtc || !new_plane_state->crtc) return false; - if (plane->state->crtc == plane_state->crtc) + if (old_plane_state->crtc == new_plane_state->crtc) return false; /* This could be refined, but currently there's no helper or driver code @@ -507,88 +506,95 @@ plane_switching_crtc(struct drm_atomic_state *state, /** * drm_atomic_plane_check - check plane state - * @plane: plane to check - * @state: plane state to check + * @old_plane_state: old plane state to check + * @new_plane_state: new plane state to check * * Provides core sanity checks for plane state. * * RETURNS: * Zero on success, error code on failure */ -static int drm_atomic_plane_check(struct drm_plane *plane, - struct drm_plane_state *state) +static int drm_atomic_plane_check(const struct drm_plane_state *old_plane_state, + const struct drm_plane_state *new_plane_state) { + struct drm_plane *plane = new_plane_state->plane; + struct drm_crtc *crtc = new_plane_state->crtc; + const struct drm_framebuffer *fb = new_plane_state->fb; unsigned int fb_width, fb_height; int ret; /* either *both* CRTC and FB must be set, or neither */ - if (state->crtc && !state->fb) { + if (crtc && !fb) { DRM_DEBUG_ATOMIC("[PLANE:%d:%s] CRTC set but no FB\n", plane->base.id, plane->name); return -EINVAL; - } else if (state->fb && !state->crtc) { + } else if (fb && !crtc) { DRM_DEBUG_ATOMIC("[PLANE:%d:%s] FB set but no CRTC\n", plane->base.id, plane->name); return -EINVAL; } /* if disabled, we don't care about the rest of the state: */ - if (!state->crtc) + if (!crtc) return 0; /* Check whether this plane is usable on this CRTC */ - if (!(plane->possible_crtcs & drm_crtc_mask(state->crtc))) { + if (!(plane->possible_crtcs & drm_crtc_mask(crtc))) { DRM_DEBUG_ATOMIC("Invalid [CRTC:%d:%s] for [PLANE:%d:%s]\n", - state->crtc->base.id, state->crtc->name, + crtc->base.id, crtc->name, plane->base.id, plane->name); return -EINVAL; } /* Check whether this plane supports the fb pixel format. */ - ret = drm_plane_check_pixel_format(plane, state->fb->format->format, - state->fb->modifier); + ret = drm_plane_check_pixel_format(plane, fb->format->format, + fb->modifier); if (ret) { struct drm_format_name_buf format_name; DRM_DEBUG_ATOMIC("[PLANE:%d:%s] invalid pixel format %s, modifier 0x%llx\n", plane->base.id, plane->name, - drm_get_format_name(state->fb->format->format, + drm_get_format_name(fb->format->format, &format_name), - state->fb->modifier); + fb->modifier); return ret; } /* Give drivers some help against integer overflows */ - if (state->crtc_w > INT_MAX || - state->crtc_x > INT_MAX - (int32_t) state->crtc_w || - state->crtc_h > INT_MAX || - state->crtc_y > INT_MAX - (int32_t) state->crtc_h) { + if (new_plane_state->crtc_w > INT_MAX || + new_plane_state->crtc_x > INT_MAX - (int32_t) new_plane_state->crtc_w || + new_plane_state->crtc_h > INT_MAX || + new_plane_state->crtc_y > INT_MAX - (int32_t) new_plane_state->crtc_h) { DRM_DEBUG_ATOMIC("[PLANE:%d:%s] invalid CRTC coordinates %ux%u+%d+%d\n", plane->base.id, plane->name, - state->crtc_w, state->crtc_h, - state->crtc_x, state->crtc_y); + new_plane_state->crtc_w, new_plane_state->crtc_h, + new_plane_state->crtc_x, new_plane_state->crtc_y); return -ERANGE; } - fb_width = state->fb->width << 16; - fb_height = state->fb->height << 16; + fb_width = fb->width << 16; + fb_height = fb->height << 16; /* Make sure source coordinates are inside the fb. */ - if (state->src_w > fb_width || - state->src_x > fb_width - state->src_w || - state->src_h > fb_height || - state->src_y > fb_height - state->src_h) { + if (new_plane_state->src_w > fb_width || + new_plane_state->src_x > fb_width - new_plane_state->src_w || + new_plane_state->src_h > fb_height || + new_plane_state->src_y > fb_height - new_plane_state->src_h) { DRM_DEBUG_ATOMIC("[PLANE:%d:%s] invalid source coordinates " "%u.%06ux%u.%06u+%u.%06u+%u.%06u (fb %ux%u)\n", plane->base.id, plane->name, - state->src_w >> 16, ((state->src_w & 0xffff) * 15625) >> 10, - state->src_h >> 16, ((state->src_h & 0xffff) * 15625) >> 10, - state->src_x >> 16, ((state->src_x & 0xffff) * 15625) >> 10, - state->src_y >> 16, ((state->src_y & 0xffff) * 15625) >> 10, - state->fb->width, state->fb->height); + new_plane_state->src_w >> 16, + ((new_plane_state->src_w & 0xffff) * 15625) >> 10, + new_plane_state->src_h >> 16, + ((new_plane_state->src_h & 0xffff) * 15625) >> 10, + new_plane_state->src_x >> 16, + ((new_plane_state->src_x & 0xffff) * 15625) >> 10, + new_plane_state->src_y >> 16, + ((new_plane_state->src_y & 0xffff) * 15625) >> 10, + fb->width, fb->height); return -ENOSPC; } - if (plane_switching_crtc(state->state, plane, state)) { + if (plane_switching_crtc(old_plane_state, new_plane_state)) { DRM_DEBUG_ATOMIC("[PLANE:%d:%s] switching CRTC directly\n", plane->base.id, plane->name); return -EINVAL; @@ -961,7 +967,8 @@ int drm_atomic_check_only(struct drm_atomic_state *state) struct drm_device *dev = state->dev; struct drm_mode_config *config = &dev->mode_config; struct drm_plane *plane; - struct drm_plane_state *plane_state; + struct drm_plane_state *old_plane_state; + struct drm_plane_state *new_plane_state; struct drm_crtc *crtc; struct drm_crtc_state *old_crtc_state; struct drm_crtc_state *new_crtc_state; @@ -971,8 +978,8 @@ int drm_atomic_check_only(struct drm_atomic_state *state) DRM_DEBUG_ATOMIC("checking %p\n", state); - for_each_new_plane_in_state(state, plane, plane_state, i) { - ret = drm_atomic_plane_check(plane, plane_state); + for_each_oldnew_plane_in_state(state, plane, old_plane_state, new_plane_state, i) { + ret = drm_atomic_plane_check(old_plane_state, new_plane_state); if (ret) { DRM_DEBUG_ATOMIC("[PLANE:%d:%s] atomic core check failed\n", plane->base.id, plane->name); -- cgit v1.2.3 From 783195ec1cada862d54dee8f312a60bcbba5c0e4 Mon Sep 17 00:00:00 2001 From: Christian König Date: Thu, 8 Nov 2018 09:39:46 +0100 Subject: drm/syncobj: disable the timeline UAPI for now v2 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Until we have sorted out all problems. v2: return -EINVAL during create if flag is set. Signed-off-by: Christian König Reviewed-by: Daniel Vetter Link: https://patchwork.freedesktop.org/patch/260937/ --- drivers/gpu/drm/drm_syncobj.c | 4 ++++ include/drm/drm_syncobj.h | 3 +++ include/uapi/drm/drm.h | 1 - 3 files changed, 7 insertions(+), 1 deletion(-) (limited to 'drivers/gpu/drm') diff --git a/drivers/gpu/drm/drm_syncobj.c b/drivers/gpu/drm/drm_syncobj.c index da8175d9c6ff..da2b85eec6cf 100644 --- a/drivers/gpu/drm/drm_syncobj.c +++ b/drivers/gpu/drm/drm_syncobj.c @@ -483,6 +483,10 @@ int drm_syncobj_create(struct drm_syncobj **out_syncobj, uint32_t flags, int ret; struct drm_syncobj *syncobj; + /* Disabled for now */ + if (flags & DRM_SYNCOBJ_CREATE_TYPE_TIMELINE) + return -EINVAL; + syncobj = kzalloc(sizeof(struct drm_syncobj), GFP_KERNEL); if (!syncobj) return -ENOMEM; diff --git a/include/drm/drm_syncobj.h b/include/drm/drm_syncobj.h index 29244cbcd05e..ffd1f4fcf519 100644 --- a/include/drm/drm_syncobj.h +++ b/include/drm/drm_syncobj.h @@ -30,6 +30,9 @@ struct drm_syncobj_cb; +/* Move the define here for the moment to avoid exposing the UAPI just yet */ +#define DRM_SYNCOBJ_CREATE_TYPE_TIMELINE (1 << 1) + enum drm_syncobj_type { DRM_SYNCOBJ_TYPE_BINARY, DRM_SYNCOBJ_TYPE_TIMELINE diff --git a/include/uapi/drm/drm.h b/include/uapi/drm/drm.h index cebdb2541eb7..300f336633f2 100644 --- a/include/uapi/drm/drm.h +++ b/include/uapi/drm/drm.h @@ -717,7 +717,6 @@ struct drm_prime_handle { struct drm_syncobj_create { __u32 handle; #define DRM_SYNCOBJ_CREATE_SIGNALED (1 << 0) -#define DRM_SYNCOBJ_CREATE_TYPE_TIMELINE (1 << 1) __u32 flags; }; -- cgit v1.2.3 From b842e2c9c0f2cb5f90f03d68963c0aae266c4c67 Mon Sep 17 00:00:00 2001 From: Paul Kocialkowski Date: Wed, 7 Nov 2018 19:18:36 +0100 Subject: drm/sun4i: tcon: Pass encoder to RGB setup function Passing the encoder to the TCON RGB setup functions allows accessing the connector from the encoder directly instead of relying on the panel. Signed-off-by: Paul Kocialkowski Signed-off-by: Maxime Ripard Link: https://patchwork.freedesktop.org/patch/msgid/20181107181843.27628-2-contact@paulk.fr --- drivers/gpu/drm/sun4i/sun4i_tcon.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers/gpu/drm') diff --git a/drivers/gpu/drm/sun4i/sun4i_tcon.c b/drivers/gpu/drm/sun4i/sun4i_tcon.c index f949287d926c..5e1f762fc3db 100644 --- a/drivers/gpu/drm/sun4i/sun4i_tcon.c +++ b/drivers/gpu/drm/sun4i/sun4i_tcon.c @@ -478,6 +478,7 @@ static void sun4i_tcon0_mode_set_lvds(struct sun4i_tcon *tcon, } static void sun4i_tcon0_mode_set_rgb(struct sun4i_tcon *tcon, + const struct drm_encoder *encoder, const struct drm_display_mode *mode) { unsigned int bp, hsync, vsync; @@ -684,7 +685,7 @@ void sun4i_tcon_mode_set(struct sun4i_tcon *tcon, sun4i_tcon0_mode_set_lvds(tcon, encoder, mode); break; case DRM_MODE_ENCODER_NONE: - sun4i_tcon0_mode_set_rgb(tcon, mode); + sun4i_tcon0_mode_set_rgb(tcon, encoder, mode); sun4i_tcon_set_mux(tcon, 0, encoder); break; case DRM_MODE_ENCODER_TVDAC: -- cgit v1.2.3 From 4843c9a208c05662811cbd0e3a0fd3e43a0ae965 Mon Sep 17 00:00:00 2001 From: Paul Kocialkowski Date: Wed, 7 Nov 2018 19:18:37 +0100 Subject: drm/sun4i: tcon: Get the connector from the encoder in RGB setup Features such as dithering and pixel data edge configuration currently rely on the panel registered with the TCON driver. However, bridges are also supported in addition to panels for RGB setup. Instead of retrieving the connector from the panel, get it from the encoder with the dedicated helper. Even in the case of bridges, the connector is registered with the encoder from our driver and is accessible when iterating connectors. Signed-off-by: Paul Kocialkowski Signed-off-by: Maxime Ripard Link: https://patchwork.freedesktop.org/patch/msgid/20181107181843.27628-3-contact@paulk.fr --- drivers/gpu/drm/sun4i/sun4i_tcon.c | 19 +++++++------------ 1 file changed, 7 insertions(+), 12 deletions(-) (limited to 'drivers/gpu/drm') diff --git a/drivers/gpu/drm/sun4i/sun4i_tcon.c b/drivers/gpu/drm/sun4i/sun4i_tcon.c index 5e1f762fc3db..262ffb6b0f82 100644 --- a/drivers/gpu/drm/sun4i/sun4i_tcon.c +++ b/drivers/gpu/drm/sun4i/sun4i_tcon.c @@ -481,6 +481,8 @@ static void sun4i_tcon0_mode_set_rgb(struct sun4i_tcon *tcon, const struct drm_encoder *encoder, const struct drm_display_mode *mode) { + struct drm_connector *connector = sun4i_tcon_get_connector(encoder); + struct drm_display_info display_info = connector->display_info; unsigned int bp, hsync, vsync; u8 clk_delay; u32 val = 0; @@ -492,8 +494,7 @@ static void sun4i_tcon0_mode_set_rgb(struct sun4i_tcon *tcon, sun4i_tcon0_mode_set_common(tcon, mode); /* Set dithering if needed */ - if (tcon->panel) - sun4i_tcon0_mode_set_dithering(tcon, tcon->panel->connector); + sun4i_tcon0_mode_set_dithering(tcon, connector); /* Adjust clock delay */ clk_delay = sun4i_tcon_get_clk_delay(mode, 0); @@ -557,17 +558,11 @@ static void sun4i_tcon0_mode_set_rgb(struct sun4i_tcon *tcon, * Following code is a way to avoid quirks all around TCON * and DOTCLOCK drivers. */ - if (tcon->panel) { - struct drm_panel *panel = tcon->panel; - struct drm_connector *connector = panel->connector; - struct drm_display_info display_info = connector->display_info; + if (display_info.bus_flags & DRM_BUS_FLAG_PIXDATA_POSEDGE) + clk_set_phase(tcon->dclk, 240); - if (display_info.bus_flags & DRM_BUS_FLAG_PIXDATA_POSEDGE) - clk_set_phase(tcon->dclk, 240); - - if (display_info.bus_flags & DRM_BUS_FLAG_PIXDATA_NEGEDGE) - clk_set_phase(tcon->dclk, 0); - } + if (display_info.bus_flags & DRM_BUS_FLAG_PIXDATA_NEGEDGE) + clk_set_phase(tcon->dclk, 0); regmap_update_bits(tcon->regs, SUN4I_TCON0_IO_POL_REG, SUN4I_TCON0_IO_POL_HSYNC_POSITIVE | SUN4I_TCON0_IO_POL_VSYNC_POSITIVE, -- cgit v1.2.3 From 65bf2d54f062474d43834cebbf48ff03c4b00080 Mon Sep 17 00:00:00 2001 From: Paul Kocialkowski Date: Wed, 7 Nov 2018 19:18:38 +0100 Subject: drm/sun4i: tcon: Support an active-low DE signal with RGB interface Some panels need an active-low data enable (DE) signal for the RGB interface. This requires flipping a bit in the TCON0 polarity register when setting up the mode for the RGB interface. Match the associated bus flag and use it to set the polarity inversion bit for the DE signal when required. Signed-off-by: Paul Kocialkowski Signed-off-by: Maxime Ripard Link: https://patchwork.freedesktop.org/patch/msgid/20181107181843.27628-4-contact@paulk.fr --- drivers/gpu/drm/sun4i/sun4i_tcon.c | 7 ++++++- drivers/gpu/drm/sun4i/sun4i_tcon.h | 1 + 2 files changed, 7 insertions(+), 1 deletion(-) (limited to 'drivers/gpu/drm') diff --git a/drivers/gpu/drm/sun4i/sun4i_tcon.c b/drivers/gpu/drm/sun4i/sun4i_tcon.c index 262ffb6b0f82..0420f5c978b9 100644 --- a/drivers/gpu/drm/sun4i/sun4i_tcon.c +++ b/drivers/gpu/drm/sun4i/sun4i_tcon.c @@ -543,6 +543,9 @@ static void sun4i_tcon0_mode_set_rgb(struct sun4i_tcon *tcon, if (mode->flags & DRM_MODE_FLAG_PVSYNC) val |= SUN4I_TCON0_IO_POL_VSYNC_POSITIVE; + if (display_info.bus_flags & DRM_BUS_FLAG_DE_LOW) + val |= SUN4I_TCON0_IO_POL_DE_NEGATIVE; + /* * On A20 and similar SoCs, the only way to achieve Positive Edge * (Rising Edge), is setting dclk clock phase to 2/3(240°). @@ -565,7 +568,9 @@ static void sun4i_tcon0_mode_set_rgb(struct sun4i_tcon *tcon, clk_set_phase(tcon->dclk, 0); regmap_update_bits(tcon->regs, SUN4I_TCON0_IO_POL_REG, - SUN4I_TCON0_IO_POL_HSYNC_POSITIVE | SUN4I_TCON0_IO_POL_VSYNC_POSITIVE, + SUN4I_TCON0_IO_POL_HSYNC_POSITIVE | + SUN4I_TCON0_IO_POL_VSYNC_POSITIVE | + SUN4I_TCON0_IO_POL_DE_NEGATIVE, val); /* Map output pins to channel 0 */ diff --git a/drivers/gpu/drm/sun4i/sun4i_tcon.h b/drivers/gpu/drm/sun4i/sun4i_tcon.h index 3d492c8be1fc..b5214d71610f 100644 --- a/drivers/gpu/drm/sun4i/sun4i_tcon.h +++ b/drivers/gpu/drm/sun4i/sun4i_tcon.h @@ -116,6 +116,7 @@ #define SUN4I_TCON0_IO_POL_REG 0x88 #define SUN4I_TCON0_IO_POL_DCLK_PHASE(phase) ((phase & 3) << 28) +#define SUN4I_TCON0_IO_POL_DE_NEGATIVE BIT(27) #define SUN4I_TCON0_IO_POL_HSYNC_POSITIVE BIT(25) #define SUN4I_TCON0_IO_POL_VSYNC_POSITIVE BIT(24) -- cgit v1.2.3 From 0560054da5673b25d56bea6c57c8d069673af73b Mon Sep 17 00:00:00 2001 From: Boris Brezillon Date: Fri, 9 Nov 2018 11:26:32 +0100 Subject: drm/vc4: ->x_scaling[1] should never be set to VC4_SCALING_NONE For the YUV conversion to work properly, ->x_scaling[1] should never be set to VC4_SCALING_NONE, but vc4_get_scaling_mode() might return VC4_SCALING_NONE if the horizontal scaling ratio exactly matches the horizontal subsampling factor. Add a test to turn VC4_SCALING_NONE into VC4_SCALING_PPF when that happens. The old ->x_scaling[0] adjustment is dropped as I couldn't find any mention to this constraint in the spec and it's proven to be unnecessary (I tested various multi-planar YUV formats with scaling disabled, and all of them worked fine without this adjustment). Fixes: fc04023fafec ("drm/vc4: Add support for YUV planes.") Signed-off-by: Boris Brezillon Reviewed-by: Eric Anholt Link: https://patchwork.freedesktop.org/patch/msgid/20181109102633.32603-1-boris.brezillon@bootlin.com --- drivers/gpu/drm/vc4/vc4_plane.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) (limited to 'drivers/gpu/drm') diff --git a/drivers/gpu/drm/vc4/vc4_plane.c b/drivers/gpu/drm/vc4/vc4_plane.c index 98fae4daa08c..6caa678edcff 100644 --- a/drivers/gpu/drm/vc4/vc4_plane.c +++ b/drivers/gpu/drm/vc4/vc4_plane.c @@ -341,12 +341,14 @@ static int vc4_plane_setup_clipping_and_scaling(struct drm_plane_state *state) vc4_get_scaling_mode(vc4_state->src_h[1], vc4_state->crtc_h); - /* YUV conversion requires that horizontal scaling be enabled, - * even on a plane that's otherwise 1:1. Looks like only PPF - * works in that case, so let's pick that one. + /* YUV conversion requires that horizontal scaling be enabled + * on the UV plane even if vc4_get_scaling_mode() returned + * VC4_SCALING_NONE (which can happen when the down-scaling + * ratio is 0.5). Let's force it to VC4_SCALING_PPF in this + * case. */ - if (vc4_state->is_unity) - vc4_state->x_scaling[0] = VC4_SCALING_PPF; + if (vc4_state->x_scaling[1] == VC4_SCALING_NONE) + vc4_state->x_scaling[1] = VC4_SCALING_PPF; } else { vc4_state->is_yuv = false; vc4_state->x_scaling[1] = VC4_SCALING_NONE; -- cgit v1.2.3 From eb8dd3abeb4dffab6c373e87d09fc3b5858ac158 Mon Sep 17 00:00:00 2001 From: Boris Brezillon Date: Fri, 9 Nov 2018 11:26:33 +0100 Subject: drm/vc4: Prefer PPF over TPZ when dst >= 2/3 src The HVS spec recommends using PPF when the downscaling ratio is between 2/3 and 1. Let's modify vc4_get_scaling_mode() to follow this recommendation. Signed-off-by: Boris Brezillon Reviewed-by: Eric Anholt Link: https://patchwork.freedesktop.org/patch/msgid/20181109102633.32603-2-boris.brezillon@bootlin.com --- drivers/gpu/drm/vc4/vc4_plane.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers/gpu/drm') diff --git a/drivers/gpu/drm/vc4/vc4_plane.c b/drivers/gpu/drm/vc4/vc4_plane.c index 6caa678edcff..1728fb7d00ba 100644 --- a/drivers/gpu/drm/vc4/vc4_plane.c +++ b/drivers/gpu/drm/vc4/vc4_plane.c @@ -129,12 +129,12 @@ static const struct hvs_format *vc4_get_hvs_format(u32 drm_format) static enum vc4_scaling_mode vc4_get_scaling_mode(u32 src, u32 dst) { - if (dst > src) + if (dst == src) + return VC4_SCALING_NONE; + if (3 * dst >= 2 * src) return VC4_SCALING_PPF; - else if (dst < src) - return VC4_SCALING_TPZ; else - return VC4_SCALING_NONE; + return VC4_SCALING_TPZ; } static bool plane_enabled(struct drm_plane_state *state) -- cgit v1.2.3 From def40774f63ad446aaf5c12e2185045979c06c75 Mon Sep 17 00:00:00 2001 From: Xinyun Liu Date: Mon, 29 Oct 2018 14:18:25 +0800 Subject: drm/i915/gvt: not to touch undefined MOCS registers Some engines are not available for all Gens. eg, Gen11 introduced VCS3/VCS4/VECS2, and VCS2 is not supported on some Gen9 machines. So need to add check before access them. Signed-off-by: Xinyun Liu Signed-off-by: Yakui Zhao Signed-off-by: Zhenyu Wang --- drivers/gpu/drm/i915/gvt/mmio_context.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers/gpu/drm') diff --git a/drivers/gpu/drm/i915/gvt/mmio_context.c b/drivers/gpu/drm/i915/gvt/mmio_context.c index 088a62ab2bc8..cdd366d44938 100644 --- a/drivers/gpu/drm/i915/gvt/mmio_context.c +++ b/drivers/gpu/drm/i915/gvt/mmio_context.c @@ -171,6 +171,8 @@ static void load_render_mocs(struct drm_i915_private *dev_priv) int ring_id, i; for (ring_id = 0; ring_id < ARRAY_SIZE(regs); ring_id++) { + if (!HAS_ENGINE(dev_priv, ring_id)) + continue; offset.reg = regs[ring_id]; for (i = 0; i < GEN9_MOCS_SIZE; i++) { gen9_render_mocs.control_table[ring_id][i] = -- cgit v1.2.3 From f3be657d96b0709c832b165501170f072882df3c Mon Sep 17 00:00:00 2001 From: Hang Yuan Date: Tue, 30 Oct 2018 13:12:23 +0800 Subject: drm/i915/gvt: ensure gpu is powered before do i915_gem_gtt_insert i915_gem_gtt_insert may evict some vmas and access HW if ggtt vm space is not enough. So add mmio_hw_access_pre before invoke i915_gem_gtt_insert to avoid call trace like below in vgpu create/ destroy test. WARNING: CPU: 6 PID: 8720 at drivers/gpu/drm/i915/intel_drv.h:1768 assert_rpm_wakelock_held.part.2+0x27/0x30 [i915] RPM wakelock ref not held during HW access Call Trace: [] dump_stack+0x19/0x1b [] __warn+0xd8/0x100 [] warn_slowpath_fmt+0x5f/0x80 [] assert_rpm_wakelock_held.part.2+0x27/0x30 [i915] [] intel_runtime_pm_get_noresume+0x6f/0x80 [i915] [] i915_gem_request_alloc+0x2dd/0x3c0 [i915] [] i915_gem_switch_to_kernel_context+0xae/0x1d0 [i915] [] ggtt_flush+0x12/0x30 [i915] [] i915_gem_evict_something+0x25f/0x470 [i915] [] i915_gem_gtt_insert+0x15c/0x1c0 [i915] [] alloc_gm+0xa7/0x160 [i915] [] intel_vgpu_alloc_resource+0x1ad/0x410 [i915] [] intel_gvt_create_vgpu+0x16c/0x260 [i915] [] intel_vgpu_create+0x50/0x140 [kvmgt] [] mdev_device_create+0x1aa/0x2e0 [mdev] v2: use mmio_hw_access_pre/post Signed-off-by: Hang Yuan Signed-off-by: Zhenyu Wang --- drivers/gpu/drm/i915/gvt/aperture_gm.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers/gpu/drm') diff --git a/drivers/gpu/drm/i915/gvt/aperture_gm.c b/drivers/gpu/drm/i915/gvt/aperture_gm.c index fe754022e356..359d37d5c958 100644 --- a/drivers/gpu/drm/i915/gvt/aperture_gm.c +++ b/drivers/gpu/drm/i915/gvt/aperture_gm.c @@ -61,10 +61,12 @@ static int alloc_gm(struct intel_vgpu *vgpu, bool high_gm) } mutex_lock(&dev_priv->drm.struct_mutex); + mmio_hw_access_pre(dev_priv); ret = i915_gem_gtt_insert(&dev_priv->ggtt.vm, node, size, I915_GTT_PAGE_SIZE, I915_COLOR_UNEVICTABLE, start, end, flags); + mmio_hw_access_post(dev_priv); mutex_unlock(&dev_priv->drm.struct_mutex); if (ret) gvt_err("fail to alloc %s gm space from host\n", -- cgit v1.2.3 From 131280a162e7fc2a539bb939efd28dd0b964c62c Mon Sep 17 00:00:00 2001 From: Eric Anholt Date: Thu, 8 Nov 2018 08:04:22 -0800 Subject: drm: Revert syncobj timeline changes. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Daniel suggested I submit this, since we're still seeing regressions from it. This is a revert to before 48197bc564c7 ("drm: add syncobj timeline support v9") and its followon fixes. Fixes this on first V3D testcase execution: [ 48.767088] ============================================ [ 48.772410] WARNING: possible recursive locking detected [ 48.777739] 4.19.0-rc6+ #489 Not tainted [ 48.781668] -------------------------------------------- [ 48.786993] shader_runner/3284 is trying to acquire lock: [ 48.792408] ce309d7f (&(&array->lock)->rlock){....}, at: dma_fence_add_callback+0x30/0x23c [ 48.800714] [ 48.800714] but task is already holding lock: [ 48.806559] c5952bd3 (&(&array->lock)->rlock){....}, at: dma_fence_add_callback+0x30/0x23c [ 48.814862] [ 48.814862] other info that might help us debug this: [ 48.821410] Possible unsafe locking scenario: [ 48.821410] [ 48.827338] CPU0 [ 48.829788] ---- [ 48.832239] lock(&(&array->lock)->rlock); [ 48.836434] lock(&(&array->lock)->rlock); [ 48.840640] [ 48.840640] *** DEADLOCK *** [ 48.840640] [ 48.846582] May be due to missing lock nesting notation [ 130.763560] 1 lock held by cts-runner/3270: [ 130.767745] #0: 7834b793 (&(&array->lock)->rlock){-...}, at: dma_fence_add_callback+0x30/0x23c [ 130.776461] stack backtrace: [ 130.780825] CPU: 1 PID: 3270 Comm: cts-runner Not tainted 4.19.0-rc6+ #486 [ 130.787706] Hardware name: Broadcom STB (Flattened Device Tree) [ 130.793645] [] (unwind_backtrace) from [] (show_stack+0x10/0x14) [ 130.801404] [] (show_stack) from [] (dump_stack+0xa8/0xd4) [ 130.808642] [] (dump_stack) from [] (__lock_acquire+0x848/0x1a68) [ 130.816483] [] (__lock_acquire) from [] (lock_acquire+0xd8/0x22c) [ 130.824326] [] (lock_acquire) from [] (_raw_spin_lock_irqsave+0x54/0x68) [ 130.832777] [] (_raw_spin_lock_irqsave) from [] (dma_fence_add_callback+0x30/0x23c) [ 130.842183] [] (dma_fence_add_callback) from [] (dma_fence_array_enable_signaling+0x58/0xec) [ 130.852371] [] (dma_fence_array_enable_signaling) from [] (dma_fence_add_callback+0xe8/0x23c) [ 130.862647] [] (dma_fence_add_callback) from [] (drm_syncobj_wait_ioctl+0x518/0x614) [ 130.872143] [] (drm_syncobj_wait_ioctl) from [] (drm_ioctl_kernel+0xb0/0xf0) [ 130.880940] [] (drm_ioctl_kernel) from [] (drm_ioctl+0x1d8/0x390) [ 130.888782] [] (drm_ioctl) from [] (do_vfs_ioctl+0xb0/0x8ac) [ 130.896187] [] (do_vfs_ioctl) from [] (ksys_ioctl+0x34/0x60) [ 130.903593] [] (ksys_ioctl) from [] (ret_fast_syscall+0x0/0x28) Cc: Chunming Zhou Cc: Christian König Cc: Daniel Vetter Signed-off-by: Eric Anholt Acked-by: Christian König Signed-off-by: Christian König Link: https://patchwork.freedesktop.org/patch/261044/ --- drivers/gpu/drm/drm_syncobj.c | 359 +++++++++--------------------------------- include/drm/drm_syncobj.h | 76 ++++----- 2 files changed, 105 insertions(+), 330 deletions(-) (limited to 'drivers/gpu/drm') diff --git a/drivers/gpu/drm/drm_syncobj.c b/drivers/gpu/drm/drm_syncobj.c index da2b85eec6cf..90e0a6dce086 100644 --- a/drivers/gpu/drm/drm_syncobj.c +++ b/drivers/gpu/drm/drm_syncobj.c @@ -56,9 +56,6 @@ #include "drm_internal.h" #include -/* merge normal syncobj to timeline syncobj, the point interval is 1 */ -#define DRM_SYNCOBJ_BINARY_POINT 1 - struct drm_syncobj_stub_fence { struct dma_fence base; spinlock_t lock; @@ -74,29 +71,7 @@ static const struct dma_fence_ops drm_syncobj_stub_fence_ops = { .get_timeline_name = drm_syncobj_stub_fence_get_name, }; -struct drm_syncobj_signal_pt { - struct dma_fence_array *fence_array; - u64 value; - struct list_head list; -}; - -static DEFINE_SPINLOCK(signaled_fence_lock); -static struct dma_fence signaled_fence; -static struct dma_fence *drm_syncobj_get_stub_fence(void) -{ - spin_lock(&signaled_fence_lock); - if (!signaled_fence.ops) { - dma_fence_init(&signaled_fence, - &drm_syncobj_stub_fence_ops, - &signaled_fence_lock, - 0, 0); - dma_fence_signal_locked(&signaled_fence); - } - spin_unlock(&signaled_fence_lock); - - return dma_fence_get(&signaled_fence); -} /** * drm_syncobj_find - lookup and reference a sync object. * @file_private: drm file private pointer @@ -123,27 +98,6 @@ struct drm_syncobj *drm_syncobj_find(struct drm_file *file_private, } EXPORT_SYMBOL(drm_syncobj_find); -static struct dma_fence * -drm_syncobj_find_signal_pt_for_point(struct drm_syncobj *syncobj, - uint64_t point) -{ - struct drm_syncobj_signal_pt *signal_pt; - - if ((syncobj->type == DRM_SYNCOBJ_TYPE_TIMELINE) && - (point <= syncobj->timeline)) - return drm_syncobj_get_stub_fence(); - - list_for_each_entry(signal_pt, &syncobj->signal_pt_list, list) { - if (point > signal_pt->value) - continue; - if ((syncobj->type == DRM_SYNCOBJ_TYPE_BINARY) && - (point != signal_pt->value)) - continue; - return dma_fence_get(&signal_pt->fence_array->base); - } - return NULL; -} - static void drm_syncobj_add_callback_locked(struct drm_syncobj *syncobj, struct drm_syncobj_cb *cb, drm_syncobj_func_t func) @@ -152,158 +106,53 @@ static void drm_syncobj_add_callback_locked(struct drm_syncobj *syncobj, list_add_tail(&cb->node, &syncobj->cb_list); } -static void drm_syncobj_fence_get_or_add_callback(struct drm_syncobj *syncobj, - struct dma_fence **fence, - struct drm_syncobj_cb *cb, - drm_syncobj_func_t func) +static int drm_syncobj_fence_get_or_add_callback(struct drm_syncobj *syncobj, + struct dma_fence **fence, + struct drm_syncobj_cb *cb, + drm_syncobj_func_t func) { - u64 pt_value = 0; - - WARN_ON(*fence); + int ret; - if (syncobj->type == DRM_SYNCOBJ_TYPE_BINARY) { - /*BINARY syncobj always wait on last pt */ - pt_value = syncobj->signal_point; + *fence = drm_syncobj_fence_get(syncobj); + if (*fence) + return 1; - if (pt_value == 0) - pt_value += DRM_SYNCOBJ_BINARY_POINT; - } - - mutex_lock(&syncobj->cb_mutex); - spin_lock(&syncobj->pt_lock); - *fence = drm_syncobj_find_signal_pt_for_point(syncobj, pt_value); - spin_unlock(&syncobj->pt_lock); - if (!*fence) + spin_lock(&syncobj->lock); + /* We've already tried once to get a fence and failed. Now that we + * have the lock, try one more time just to be sure we don't add a + * callback when a fence has already been set. + */ + if (syncobj->fence) { + *fence = dma_fence_get(rcu_dereference_protected(syncobj->fence, + lockdep_is_held(&syncobj->lock))); + ret = 1; + } else { + *fence = NULL; drm_syncobj_add_callback_locked(syncobj, cb, func); - mutex_unlock(&syncobj->cb_mutex); -} - -static void drm_syncobj_remove_callback(struct drm_syncobj *syncobj, - struct drm_syncobj_cb *cb) -{ - mutex_lock(&syncobj->cb_mutex); - list_del_init(&cb->node); - mutex_unlock(&syncobj->cb_mutex); -} + ret = 0; + } + spin_unlock(&syncobj->lock); -static void drm_syncobj_init(struct drm_syncobj *syncobj) -{ - spin_lock(&syncobj->pt_lock); - syncobj->timeline_context = dma_fence_context_alloc(1); - syncobj->timeline = 0; - syncobj->signal_point = 0; - init_waitqueue_head(&syncobj->wq); - - INIT_LIST_HEAD(&syncobj->signal_pt_list); - spin_unlock(&syncobj->pt_lock); + return ret; } -static void drm_syncobj_fini(struct drm_syncobj *syncobj) +void drm_syncobj_add_callback(struct drm_syncobj *syncobj, + struct drm_syncobj_cb *cb, + drm_syncobj_func_t func) { - struct drm_syncobj_signal_pt *signal_pt = NULL, *tmp; - - spin_lock(&syncobj->pt_lock); - list_for_each_entry_safe(signal_pt, tmp, - &syncobj->signal_pt_list, list) { - list_del(&signal_pt->list); - dma_fence_put(&signal_pt->fence_array->base); - kfree(signal_pt); - } - spin_unlock(&syncobj->pt_lock); + spin_lock(&syncobj->lock); + drm_syncobj_add_callback_locked(syncobj, cb, func); + spin_unlock(&syncobj->lock); } -static int drm_syncobj_create_signal_pt(struct drm_syncobj *syncobj, - struct dma_fence *fence, - u64 point) +void drm_syncobj_remove_callback(struct drm_syncobj *syncobj, + struct drm_syncobj_cb *cb) { - struct drm_syncobj_signal_pt *signal_pt = - kzalloc(sizeof(struct drm_syncobj_signal_pt), GFP_KERNEL); - struct drm_syncobj_signal_pt *tail_pt; - struct dma_fence **fences; - int num_fences = 0; - int ret = 0, i; - - if (!signal_pt) - return -ENOMEM; - if (!fence) - goto out; - - fences = kmalloc_array(sizeof(void *), 2, GFP_KERNEL); - if (!fences) { - ret = -ENOMEM; - goto out; - } - fences[num_fences++] = dma_fence_get(fence); - /* timeline syncobj must take this dependency */ - if (syncobj->type == DRM_SYNCOBJ_TYPE_TIMELINE) { - spin_lock(&syncobj->pt_lock); - if (!list_empty(&syncobj->signal_pt_list)) { - tail_pt = list_last_entry(&syncobj->signal_pt_list, - struct drm_syncobj_signal_pt, list); - fences[num_fences++] = - dma_fence_get(&tail_pt->fence_array->base); - } - spin_unlock(&syncobj->pt_lock); - } - signal_pt->fence_array = dma_fence_array_create(num_fences, fences, - syncobj->timeline_context, - point, false); - if (!signal_pt->fence_array) { - ret = -ENOMEM; - goto fail; - } - - spin_lock(&syncobj->pt_lock); - if (syncobj->signal_point >= point) { - DRM_WARN("A later signal is ready!"); - spin_unlock(&syncobj->pt_lock); - goto exist; - } - signal_pt->value = point; - list_add_tail(&signal_pt->list, &syncobj->signal_pt_list); - syncobj->signal_point = point; - spin_unlock(&syncobj->pt_lock); - wake_up_all(&syncobj->wq); - - return 0; -exist: - dma_fence_put(&signal_pt->fence_array->base); -fail: - for (i = 0; i < num_fences; i++) - dma_fence_put(fences[i]); - kfree(fences); -out: - kfree(signal_pt); - return ret; + spin_lock(&syncobj->lock); + list_del_init(&cb->node); + spin_unlock(&syncobj->lock); } -static void drm_syncobj_garbage_collection(struct drm_syncobj *syncobj) -{ - struct drm_syncobj_signal_pt *signal_pt, *tmp, *tail_pt; - - spin_lock(&syncobj->pt_lock); - tail_pt = list_last_entry(&syncobj->signal_pt_list, - struct drm_syncobj_signal_pt, - list); - list_for_each_entry_safe(signal_pt, tmp, - &syncobj->signal_pt_list, list) { - if (syncobj->type == DRM_SYNCOBJ_TYPE_BINARY && - signal_pt == tail_pt) - continue; - if (dma_fence_is_signaled(&signal_pt->fence_array->base)) { - syncobj->timeline = signal_pt->value; - list_del(&signal_pt->list); - dma_fence_put(&signal_pt->fence_array->base); - kfree(signal_pt); - } else { - /*signal_pt is in order in list, from small to big, so - * the later must not be signal either */ - break; - } - } - - spin_unlock(&syncobj->pt_lock); -} /** * drm_syncobj_replace_fence - replace fence in a sync object. * @syncobj: Sync object to replace fence in @@ -316,30 +165,28 @@ void drm_syncobj_replace_fence(struct drm_syncobj *syncobj, u64 point, struct dma_fence *fence) { - u64 pt_value = point; - - drm_syncobj_garbage_collection(syncobj); - if (syncobj->type == DRM_SYNCOBJ_TYPE_BINARY) { - if (!fence) { - drm_syncobj_fini(syncobj); - drm_syncobj_init(syncobj); - return; - } - pt_value = syncobj->signal_point + - DRM_SYNCOBJ_BINARY_POINT; - } - drm_syncobj_create_signal_pt(syncobj, fence, pt_value); - if (fence) { - struct drm_syncobj_cb *cur, *tmp; - LIST_HEAD(cb_list); + struct dma_fence *old_fence; + struct drm_syncobj_cb *cur, *tmp; + + if (fence) + dma_fence_get(fence); + + spin_lock(&syncobj->lock); + + old_fence = rcu_dereference_protected(syncobj->fence, + lockdep_is_held(&syncobj->lock)); + rcu_assign_pointer(syncobj->fence, fence); - mutex_lock(&syncobj->cb_mutex); + if (fence != old_fence) { list_for_each_entry_safe(cur, tmp, &syncobj->cb_list, node) { list_del_init(&cur->node); cur->func(syncobj, cur); } - mutex_unlock(&syncobj->cb_mutex); } + + spin_unlock(&syncobj->lock); + + dma_fence_put(old_fence); } EXPORT_SYMBOL(drm_syncobj_replace_fence); @@ -362,64 +209,6 @@ static int drm_syncobj_assign_null_handle(struct drm_syncobj *syncobj) return 0; } -static int -drm_syncobj_point_get(struct drm_syncobj *syncobj, u64 point, u64 flags, - struct dma_fence **fence) -{ - int ret = 0; - - if (flags & DRM_SYNCOBJ_WAIT_FLAGS_WAIT_FOR_SUBMIT) { - ret = wait_event_interruptible(syncobj->wq, - point <= syncobj->signal_point); - if (ret < 0) - return ret; - } - spin_lock(&syncobj->pt_lock); - *fence = drm_syncobj_find_signal_pt_for_point(syncobj, point); - if (!*fence) - ret = -EINVAL; - spin_unlock(&syncobj->pt_lock); - return ret; -} - -/** - * drm_syncobj_search_fence - lookup and reference the fence in a sync object or - * in a timeline point - * @syncobj: sync object pointer - * @point: timeline point - * @flags: DRM_SYNCOBJ_WAIT_FLAGS_WAIT_FOR_SUBMIT or not - * @fence: out parameter for the fence - * - * if flags is DRM_SYNCOBJ_WAIT_FLAGS_WAIT_FOR_SUBMIT, the function will block - * here until specific timeline points is reached. - * if not, you need a submit thread and block in userspace until all future - * timeline points have materialized, only then you can submit to the kernel, - * otherwise, function will fail to return fence. - * - * Returns 0 on success or a negative error value on failure. On success @fence - * contains a reference to the fence, which must be released by calling - * dma_fence_put(). - */ -int drm_syncobj_search_fence(struct drm_syncobj *syncobj, u64 point, - u64 flags, struct dma_fence **fence) -{ - u64 pt_value = point; - - if (!syncobj) - return -ENOENT; - - drm_syncobj_garbage_collection(syncobj); - if (syncobj->type == DRM_SYNCOBJ_TYPE_BINARY) { - /*BINARY syncobj always wait on last pt */ - pt_value = syncobj->signal_point; - - if (pt_value == 0) - pt_value += DRM_SYNCOBJ_BINARY_POINT; - } - return drm_syncobj_point_get(syncobj, pt_value, flags, fence); -} -EXPORT_SYMBOL(drm_syncobj_search_fence); - /** * drm_syncobj_find_fence - lookup and reference the fence in a sync object * @file_private: drm file private pointer @@ -429,7 +218,7 @@ EXPORT_SYMBOL(drm_syncobj_search_fence); * @fence: out parameter for the fence * * This is just a convenience function that combines drm_syncobj_find() and - * drm_syncobj_lookup_fence(). + * drm_syncobj_fence_get(). * * Returns 0 on success or a negative error value on failure. On success @fence * contains a reference to the fence, which must be released by calling @@ -440,11 +229,16 @@ int drm_syncobj_find_fence(struct drm_file *file_private, struct dma_fence **fence) { struct drm_syncobj *syncobj = drm_syncobj_find(file_private, handle); - int ret; + int ret = 0; - ret = drm_syncobj_search_fence(syncobj, point, flags, fence); - if (syncobj) - drm_syncobj_put(syncobj); + if (!syncobj) + return -ENOENT; + + *fence = drm_syncobj_fence_get(syncobj); + if (!*fence) { + ret = -EINVAL; + } + drm_syncobj_put(syncobj); return ret; } EXPORT_SYMBOL(drm_syncobj_find_fence); @@ -460,7 +254,7 @@ void drm_syncobj_free(struct kref *kref) struct drm_syncobj *syncobj = container_of(kref, struct drm_syncobj, refcount); - drm_syncobj_fini(syncobj); + drm_syncobj_replace_fence(syncobj, 0, NULL); kfree(syncobj); } EXPORT_SYMBOL(drm_syncobj_free); @@ -493,13 +287,7 @@ int drm_syncobj_create(struct drm_syncobj **out_syncobj, uint32_t flags, kref_init(&syncobj->refcount); INIT_LIST_HEAD(&syncobj->cb_list); - spin_lock_init(&syncobj->pt_lock); - mutex_init(&syncobj->cb_mutex); - if (flags & DRM_SYNCOBJ_CREATE_TYPE_TIMELINE) - syncobj->type = DRM_SYNCOBJ_TYPE_TIMELINE; - else - syncobj->type = DRM_SYNCOBJ_TYPE_BINARY; - drm_syncobj_init(syncobj); + spin_lock_init(&syncobj->lock); if (flags & DRM_SYNCOBJ_CREATE_SIGNALED) { ret = drm_syncobj_assign_null_handle(syncobj); @@ -782,8 +570,7 @@ drm_syncobj_create_ioctl(struct drm_device *dev, void *data, return -EOPNOTSUPP; /* no valid flags yet */ - if (args->flags & ~(DRM_SYNCOBJ_CREATE_SIGNALED | - DRM_SYNCOBJ_CREATE_TYPE_TIMELINE)) + if (args->flags & ~DRM_SYNCOBJ_CREATE_SIGNALED) return -EINVAL; return drm_syncobj_create_as_handle(file_private, @@ -876,8 +663,9 @@ static void syncobj_wait_syncobj_func(struct drm_syncobj *syncobj, struct syncobj_wait_entry *wait = container_of(cb, struct syncobj_wait_entry, syncobj_cb); - drm_syncobj_search_fence(syncobj, 0, 0, &wait->fence); - + /* This happens inside the syncobj lock */ + wait->fence = dma_fence_get(rcu_dereference_protected(syncobj->fence, + lockdep_is_held(&syncobj->lock))); wake_up_process(wait->task); } @@ -903,8 +691,7 @@ static signed long drm_syncobj_array_wait_timeout(struct drm_syncobj **syncobjs, signaled_count = 0; for (i = 0; i < count; ++i) { entries[i].task = current; - drm_syncobj_search_fence(syncobjs[i], 0, 0, - &entries[i].fence); + entries[i].fence = drm_syncobj_fence_get(syncobjs[i]); if (!entries[i].fence) { if (flags & DRM_SYNCOBJ_WAIT_FLAGS_WAIT_FOR_SUBMIT) { continue; @@ -935,9 +722,6 @@ static signed long drm_syncobj_array_wait_timeout(struct drm_syncobj **syncobjs, if (flags & DRM_SYNCOBJ_WAIT_FLAGS_WAIT_FOR_SUBMIT) { for (i = 0; i < count; ++i) { - if (entries[i].fence) - continue; - drm_syncobj_fence_get_or_add_callback(syncobjs[i], &entries[i].fence, &entries[i].syncobj_cb, @@ -1169,13 +953,12 @@ drm_syncobj_reset_ioctl(struct drm_device *dev, void *data, if (ret < 0) return ret; - for (i = 0; i < args->count_handles; i++) { - drm_syncobj_fini(syncobjs[i]); - drm_syncobj_init(syncobjs[i]); - } + for (i = 0; i < args->count_handles; i++) + drm_syncobj_replace_fence(syncobjs[i], 0, NULL); + drm_syncobj_array_free(syncobjs, args->count_handles); - return ret; + return 0; } int diff --git a/include/drm/drm_syncobj.h b/include/drm/drm_syncobj.h index ffd1f4fcf519..2eda44def639 100644 --- a/include/drm/drm_syncobj.h +++ b/include/drm/drm_syncobj.h @@ -30,18 +30,10 @@ struct drm_syncobj_cb; -/* Move the define here for the moment to avoid exposing the UAPI just yet */ -#define DRM_SYNCOBJ_CREATE_TYPE_TIMELINE (1 << 1) - -enum drm_syncobj_type { - DRM_SYNCOBJ_TYPE_BINARY, - DRM_SYNCOBJ_TYPE_TIMELINE -}; - /** * struct drm_syncobj - sync object. * - * This structure defines a generic sync object which is timeline based. + * This structure defines a generic sync object which wraps a &dma_fence. */ struct drm_syncobj { /** @@ -49,42 +41,21 @@ struct drm_syncobj { */ struct kref refcount; /** - * @type: indicate syncobj type - */ - enum drm_syncobj_type type; - /** - * @wq: wait signal operation work queue - */ - wait_queue_head_t wq; - /** - * @timeline_context: fence context used by timeline - */ - u64 timeline_context; - /** - * @timeline: syncobj timeline value, which indicates point is signaled. + * @fence: + * NULL or a pointer to the fence bound to this object. + * + * This field should not be used directly. Use drm_syncobj_fence_get() + * and drm_syncobj_replace_fence() instead. */ - u64 timeline; + struct dma_fence __rcu *fence; /** - * @signal_point: which indicates the latest signaler point. + * @cb_list: List of callbacks to call when the &fence gets replaced. */ - u64 signal_point; - /** - * @signal_pt_list: signaler point list. - */ - struct list_head signal_pt_list; - - /** - * @cb_list: List of callbacks to call when the &fence gets replaced. - */ struct list_head cb_list; /** - * @pt_lock: Protects pt list. - */ - spinlock_t pt_lock; - /** - * @cb_mutex: Protects syncobj cb list. + * @lock: Protects &cb_list and write-locks &fence. */ - struct mutex cb_mutex; + spinlock_t lock; /** * @file: A file backing for this syncobj. */ @@ -97,7 +68,7 @@ typedef void (*drm_syncobj_func_t)(struct drm_syncobj *syncobj, /** * struct drm_syncobj_cb - callback for drm_syncobj_add_callback * @node: used by drm_syncob_add_callback to append this struct to - * &drm_syncobj.cb_list + * &drm_syncobj.cb_list * @func: drm_syncobj_func_t to call * * This struct will be initialized by drm_syncobj_add_callback, additional @@ -135,6 +106,29 @@ drm_syncobj_put(struct drm_syncobj *obj) kref_put(&obj->refcount, drm_syncobj_free); } +/** + * drm_syncobj_fence_get - get a reference to a fence in a sync object + * @syncobj: sync object. + * + * This acquires additional reference to &drm_syncobj.fence contained in @obj, + * if not NULL. It is illegal to call this without already holding a reference. + * No locks required. + * + * Returns: + * Either the fence of @obj or NULL if there's none. + */ +static inline struct dma_fence * +drm_syncobj_fence_get(struct drm_syncobj *syncobj) +{ + struct dma_fence *fence; + + rcu_read_lock(); + fence = dma_fence_get_rcu_safe(&syncobj->fence); + rcu_read_unlock(); + + return fence; +} + struct drm_syncobj *drm_syncobj_find(struct drm_file *file_private, u32 handle); void drm_syncobj_replace_fence(struct drm_syncobj *syncobj, u64 point, @@ -148,7 +142,5 @@ int drm_syncobj_create(struct drm_syncobj **out_syncobj, uint32_t flags, int drm_syncobj_get_handle(struct drm_file *file_private, struct drm_syncobj *syncobj, u32 *handle); int drm_syncobj_get_fd(struct drm_syncobj *syncobj, int *p_fd); -int drm_syncobj_search_fence(struct drm_syncobj *syncobj, u64 point, u64 flags, - struct dma_fence **fence); #endif -- cgit v1.2.3 From daedaa33d9c578220b311fbad3748d3ecd5a8f66 Mon Sep 17 00:00:00 2001 From: Lu Baolu Date: Mon, 12 Nov 2018 14:40:08 +0800 Subject: iommu/vtd: Cleanup dma_remapping.h header Commit e61d98d8dad00 ("x64, x2apic/intr-remap: Intel vt-d, IOMMU code reorganization") moved dma_remapping.h from drivers/pci/ to current place. It is entirely VT-d specific, but uses a generic name. This merges dma_remapping.h with include/linux/intel-iommu.h and removes dma_remapping.h as the result. Cc: Ashok Raj Cc: Jacob Pan Cc: Sohil Mehta Suggested-by: Christoph Hellwig Signed-off-by: Lu Baolu Reviewed-by: Christoph Hellwig Reviewed-by: Liu, Yi L Signed-off-by: Joerg Roedel --- arch/x86/kernel/tboot.c | 2 +- drivers/gpu/drm/i915/i915_gem_execbuffer.c | 2 +- drivers/gpu/drm/i915/intel_display.c | 2 +- drivers/gpu/drm/vmwgfx/vmwgfx_drv.c | 2 +- drivers/misc/mic/scif/scif_rma.c | 2 +- drivers/misc/mic/scif/scif_rma.h | 2 +- include/linux/dma_remapping.h | 58 ------------------------------ include/linux/intel-iommu.h | 49 +++++++++++++++++++++++-- 8 files changed, 53 insertions(+), 66 deletions(-) delete mode 100644 include/linux/dma_remapping.h (limited to 'drivers/gpu/drm') diff --git a/arch/x86/kernel/tboot.c b/arch/x86/kernel/tboot.c index a2486f444073..6e5ef8fb8a02 100644 --- a/arch/x86/kernel/tboot.c +++ b/arch/x86/kernel/tboot.c @@ -19,7 +19,7 @@ * */ -#include +#include #include #include #include diff --git a/drivers/gpu/drm/i915/i915_gem_execbuffer.c b/drivers/gpu/drm/i915/i915_gem_execbuffer.c index 1aaccbe7e1de..1c5d04f002bc 100644 --- a/drivers/gpu/drm/i915/i915_gem_execbuffer.c +++ b/drivers/gpu/drm/i915/i915_gem_execbuffer.c @@ -26,7 +26,7 @@ * */ -#include +#include #include #include #include diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 23d8008a93bb..389d6618c2d5 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -47,7 +47,7 @@ #include #include #include -#include +#include #include /* Primary plane formats for gen <= 3 */ diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c index 61a84b958d67..c3e80a3b09fc 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c @@ -34,7 +34,7 @@ #include #include #include -#include +#include #define VMWGFX_DRIVER_DESC "Linux drm driver for VMware graphics devices" #define VMWGFX_CHIP_SVGAII 0 diff --git a/drivers/misc/mic/scif/scif_rma.c b/drivers/misc/mic/scif/scif_rma.c index c824329f7012..b441f6b0c743 100644 --- a/drivers/misc/mic/scif/scif_rma.c +++ b/drivers/misc/mic/scif/scif_rma.c @@ -15,7 +15,7 @@ * Intel SCIF driver. * */ -#include +#include #include #include #include diff --git a/drivers/misc/mic/scif/scif_rma.h b/drivers/misc/mic/scif/scif_rma.h index fa6722279196..d90a06d4e93b 100644 --- a/drivers/misc/mic/scif/scif_rma.h +++ b/drivers/misc/mic/scif/scif_rma.h @@ -53,7 +53,7 @@ #ifndef SCIF_RMA_H #define SCIF_RMA_H -#include +#include #include #include "../bus/scif_bus.h" diff --git a/include/linux/dma_remapping.h b/include/linux/dma_remapping.h deleted file mode 100644 index 21b3e7d33d68..000000000000 --- a/include/linux/dma_remapping.h +++ /dev/null @@ -1,58 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -#ifndef _DMA_REMAPPING_H -#define _DMA_REMAPPING_H - -/* - * VT-d hardware uses 4KiB page size regardless of host page size. - */ -#define VTD_PAGE_SHIFT (12) -#define VTD_PAGE_SIZE (1UL << VTD_PAGE_SHIFT) -#define VTD_PAGE_MASK (((u64)-1) << VTD_PAGE_SHIFT) -#define VTD_PAGE_ALIGN(addr) (((addr) + VTD_PAGE_SIZE - 1) & VTD_PAGE_MASK) - -#define VTD_STRIDE_SHIFT (9) -#define VTD_STRIDE_MASK (((u64)-1) << VTD_STRIDE_SHIFT) - -#define DMA_PTE_READ (1) -#define DMA_PTE_WRITE (2) -#define DMA_PTE_LARGE_PAGE (1 << 7) -#define DMA_PTE_SNP (1 << 11) - -#define CONTEXT_TT_MULTI_LEVEL 0 -#define CONTEXT_TT_DEV_IOTLB 1 -#define CONTEXT_TT_PASS_THROUGH 2 -/* Extended context entry types */ -#define CONTEXT_TT_PT_PASID 4 -#define CONTEXT_TT_PT_PASID_DEV_IOTLB 5 -#define CONTEXT_TT_MASK (7ULL << 2) - -#define CONTEXT_DINVE (1ULL << 8) -#define CONTEXT_PRS (1ULL << 9) -#define CONTEXT_PASIDE (1ULL << 11) - -struct intel_iommu; -struct dmar_domain; -struct root_entry; - - -#ifdef CONFIG_INTEL_IOMMU -extern int iommu_calculate_agaw(struct intel_iommu *iommu); -extern int iommu_calculate_max_sagaw(struct intel_iommu *iommu); -extern int dmar_disabled; -extern int intel_iommu_enabled; -extern int intel_iommu_tboot_noforce; -#else -static inline int iommu_calculate_agaw(struct intel_iommu *iommu) -{ - return 0; -} -static inline int iommu_calculate_max_sagaw(struct intel_iommu *iommu) -{ - return 0; -} -#define dmar_disabled (1) -#define intel_iommu_enabled (0) -#endif - - -#endif diff --git a/include/linux/intel-iommu.h b/include/linux/intel-iommu.h index b0ae25837361..a58bc05d6798 100644 --- a/include/linux/intel-iommu.h +++ b/include/linux/intel-iommu.h @@ -26,7 +26,6 @@ #include #include #include -#include #include #include #include @@ -37,9 +36,36 @@ #include /* - * Intel IOMMU register specification per version 1.0 public spec. + * VT-d hardware uses 4KiB page size regardless of host page size. */ +#define VTD_PAGE_SHIFT (12) +#define VTD_PAGE_SIZE (1UL << VTD_PAGE_SHIFT) +#define VTD_PAGE_MASK (((u64)-1) << VTD_PAGE_SHIFT) +#define VTD_PAGE_ALIGN(addr) (((addr) + VTD_PAGE_SIZE - 1) & VTD_PAGE_MASK) + +#define VTD_STRIDE_SHIFT (9) +#define VTD_STRIDE_MASK (((u64)-1) << VTD_STRIDE_SHIFT) + +#define DMA_PTE_READ (1) +#define DMA_PTE_WRITE (2) +#define DMA_PTE_LARGE_PAGE (1 << 7) +#define DMA_PTE_SNP (1 << 11) + +#define CONTEXT_TT_MULTI_LEVEL 0 +#define CONTEXT_TT_DEV_IOTLB 1 +#define CONTEXT_TT_PASS_THROUGH 2 +/* Extended context entry types */ +#define CONTEXT_TT_PT_PASID 4 +#define CONTEXT_TT_PT_PASID_DEV_IOTLB 5 +#define CONTEXT_TT_MASK (7ULL << 2) + +#define CONTEXT_DINVE (1ULL << 8) +#define CONTEXT_PRS (1ULL << 9) +#define CONTEXT_PASIDE (1ULL << 11) +/* + * Intel IOMMU register specification per version 1.0 public spec. + */ #define DMAR_VER_REG 0x0 /* Arch version supported by this IOMMU */ #define DMAR_CAP_REG 0x8 /* Hardware supported capabilities */ #define DMAR_ECAP_REG 0x10 /* Extended capabilities supported */ @@ -632,4 +658,23 @@ bool context_present(struct context_entry *context); struct context_entry *iommu_context_addr(struct intel_iommu *iommu, u8 bus, u8 devfn, int alloc); +#ifdef CONFIG_INTEL_IOMMU +extern int iommu_calculate_agaw(struct intel_iommu *iommu); +extern int iommu_calculate_max_sagaw(struct intel_iommu *iommu); +extern int dmar_disabled; +extern int intel_iommu_enabled; +extern int intel_iommu_tboot_noforce; +#else +static inline int iommu_calculate_agaw(struct intel_iommu *iommu) +{ + return 0; +} +static inline int iommu_calculate_max_sagaw(struct intel_iommu *iommu) +{ + return 0; +} +#define dmar_disabled (1) +#define intel_iommu_enabled (0) +#endif + #endif -- cgit v1.2.3 From 913240696ec64a2af2de250b1591cc45b5cea2f6 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Mon, 12 Nov 2018 15:21:30 +0000 Subject: drm/syncobj: Fix compilation following partial revert MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We need to include the revert of commit 783195ec1cad ("drm/syncobj: disable the timeline UAPI for now v2") along with undoing the change to drm/i915. Fixes: 131280a162e7 ("drm: Revert syncobj timeline changes.") Cc: Christian König Cc: Daniel Vetter Cc: Chunming Zhou Cc: Eric Anholt Cc: Joonas Lahtinen Cc: Maarten Lankhorst Cc: Maxime Ripard Cc: Sean Paul Cc: David Airlie Reviewed-by: Christian König Signed-off-by: Chris Wilson Signed-off-by: Sean Paul Link: https://patchwork.freedesktop.org/patch/msgid/20181112152130.12275-1-chris@chris-wilson.co.uk --- drivers/gpu/drm/drm_syncobj.c | 4 ---- drivers/gpu/drm/i915/i915_gem_execbuffer.c | 2 +- 2 files changed, 1 insertion(+), 5 deletions(-) (limited to 'drivers/gpu/drm') diff --git a/drivers/gpu/drm/drm_syncobj.c b/drivers/gpu/drm/drm_syncobj.c index 90e0a6dce086..e2c5b3ca4824 100644 --- a/drivers/gpu/drm/drm_syncobj.c +++ b/drivers/gpu/drm/drm_syncobj.c @@ -277,10 +277,6 @@ int drm_syncobj_create(struct drm_syncobj **out_syncobj, uint32_t flags, int ret; struct drm_syncobj *syncobj; - /* Disabled for now */ - if (flags & DRM_SYNCOBJ_CREATE_TYPE_TIMELINE) - return -EINVAL; - syncobj = kzalloc(sizeof(struct drm_syncobj), GFP_KERNEL); if (!syncobj) return -ENOMEM; diff --git a/drivers/gpu/drm/i915/i915_gem_execbuffer.c b/drivers/gpu/drm/i915/i915_gem_execbuffer.c index f90a09b83370..09187286d346 100644 --- a/drivers/gpu/drm/i915/i915_gem_execbuffer.c +++ b/drivers/gpu/drm/i915/i915_gem_execbuffer.c @@ -2157,7 +2157,7 @@ await_fence_array(struct i915_execbuffer *eb, if (!(flags & I915_EXEC_FENCE_WAIT)) continue; - drm_syncobj_search_fence(syncobj, 0, 0, &fence); + fence = drm_syncobj_fence_get(syncobj); if (!fence) return -EINVAL; -- cgit v1.2.3 From 66cae477c380d1a652399908de94ec680225bbdb Mon Sep 17 00:00:00 2001 From: Maxime Jourdan Date: Mon, 5 Nov 2018 11:45:08 +0100 Subject: drm/meson: Use optional canvas provider This is the first step into converting the meson/drm driver to use the canvas module. If a canvas provider node is detected in DT, use it. Otherwise, fall back to what is currently being done. Signed-off-by: Maxime Jourdan Reviewed-by: Neil Armstrong [narmstrong: added back priv in meson_drv_unbind()] Signed-off-by: Neil Armstrong Link: https://patchwork.freedesktop.org/patch/msgid/20181105104508.23090-3-mjourdan@baylibre.com --- drivers/gpu/drm/meson/Kconfig | 1 + drivers/gpu/drm/meson/meson_crtc.c | 14 +++++++---- drivers/gpu/drm/meson/meson_drv.c | 47 +++++++++++++++++++++++-------------- drivers/gpu/drm/meson/meson_drv.h | 4 ++++ drivers/gpu/drm/meson/meson_plane.c | 8 ++++++- 5 files changed, 52 insertions(+), 22 deletions(-) (limited to 'drivers/gpu/drm') diff --git a/drivers/gpu/drm/meson/Kconfig b/drivers/gpu/drm/meson/Kconfig index 3ce51d8dfe1c..c28b69f48555 100644 --- a/drivers/gpu/drm/meson/Kconfig +++ b/drivers/gpu/drm/meson/Kconfig @@ -7,6 +7,7 @@ config DRM_MESON select DRM_GEM_CMA_HELPER select VIDEOMODE_HELPERS select REGMAP_MMIO + select MESON_CANVAS config DRM_MESON_DW_HDMI tristate "HDMI Synopsys Controller support for Amlogic Meson Display" diff --git a/drivers/gpu/drm/meson/meson_crtc.c b/drivers/gpu/drm/meson/meson_crtc.c index 05520202c967..b3bc0b0ee07f 100644 --- a/drivers/gpu/drm/meson/meson_crtc.c +++ b/drivers/gpu/drm/meson/meson_crtc.c @@ -193,10 +193,16 @@ void meson_crtc_irq(struct meson_drm *priv) } else meson_vpp_disable_interlace_vscaler_osd1(priv); - meson_canvas_setup(priv, MESON_CANVAS_ID_OSD1, - priv->viu.osd1_addr, priv->viu.osd1_stride, - priv->viu.osd1_height, MESON_CANVAS_WRAP_NONE, - MESON_CANVAS_BLKMODE_LINEAR); + if (priv->canvas) + meson_canvas_config(priv->canvas, priv->canvas_id_osd1, + priv->viu.osd1_addr, priv->viu.osd1_stride, + priv->viu.osd1_height, MESON_CANVAS_WRAP_NONE, + MESON_CANVAS_BLKMODE_LINEAR, 0); + else + meson_canvas_setup(priv, MESON_CANVAS_ID_OSD1, + priv->viu.osd1_addr, priv->viu.osd1_stride, + priv->viu.osd1_height, MESON_CANVAS_WRAP_NONE, + MESON_CANVAS_BLKMODE_LINEAR); /* Enable OSD1 */ writel_bits_relaxed(VPP_OSD1_POSTBLEND, VPP_OSD1_POSTBLEND, diff --git a/drivers/gpu/drm/meson/meson_drv.c b/drivers/gpu/drm/meson/meson_drv.c index 348b5a198b9d..3fe6edf79b5c 100644 --- a/drivers/gpu/drm/meson/meson_drv.c +++ b/drivers/gpu/drm/meson/meson_drv.c @@ -208,24 +208,33 @@ static int meson_drv_bind_master(struct device *dev, bool has_components) goto free_drm; } - res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "dmc"); - if (!res) { - ret = -EINVAL; - goto free_drm; - } - /* Simply ioremap since it may be a shared register zone */ - regs = devm_ioremap(dev, res->start, resource_size(res)); - if (!regs) { - ret = -EADDRNOTAVAIL; - goto free_drm; - } + priv->canvas = meson_canvas_get(dev); + if (!IS_ERR(priv->canvas)) { + ret = meson_canvas_alloc(priv->canvas, &priv->canvas_id_osd1); + if (ret) + goto free_drm; + } else { + priv->canvas = NULL; - priv->dmc = devm_regmap_init_mmio(dev, regs, - &meson_regmap_config); - if (IS_ERR(priv->dmc)) { - dev_err(&pdev->dev, "Couldn't create the DMC regmap\n"); - ret = PTR_ERR(priv->dmc); - goto free_drm; + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "dmc"); + if (!res) { + ret = -EINVAL; + goto free_drm; + } + /* Simply ioremap since it may be a shared register zone */ + regs = devm_ioremap(dev, res->start, resource_size(res)); + if (!regs) { + ret = -EADDRNOTAVAIL; + goto free_drm; + } + + priv->dmc = devm_regmap_init_mmio(dev, regs, + &meson_regmap_config); + if (IS_ERR(priv->dmc)) { + dev_err(&pdev->dev, "Couldn't create the DMC regmap\n"); + ret = PTR_ERR(priv->dmc); + goto free_drm; + } } priv->vsync_irq = platform_get_irq(pdev, 0); @@ -300,6 +309,10 @@ static int meson_drv_bind(struct device *dev) static void meson_drv_unbind(struct device *dev) { struct drm_device *drm = dev_get_drvdata(dev); + struct meson_drm *priv = drm->dev_private; + + if (priv->canvas) + meson_canvas_free(priv->canvas, priv->canvas_id_osd1); drm_dev_unregister(drm); drm_kms_helper_poll_fini(drm); diff --git a/drivers/gpu/drm/meson/meson_drv.h b/drivers/gpu/drm/meson/meson_drv.h index aab96260da9f..747a996dcbdd 100644 --- a/drivers/gpu/drm/meson/meson_drv.h +++ b/drivers/gpu/drm/meson/meson_drv.h @@ -22,6 +22,7 @@ #include #include #include +#include #include struct meson_drm { @@ -31,6 +32,9 @@ struct meson_drm { struct regmap *dmc; int vsync_irq; + struct meson_canvas *canvas; + u8 canvas_id_osd1; + struct drm_device *drm; struct drm_crtc *crtc; struct drm_plane *primary_plane; diff --git a/drivers/gpu/drm/meson/meson_plane.c b/drivers/gpu/drm/meson/meson_plane.c index 12c80dfcff59..51bec8e98a39 100644 --- a/drivers/gpu/drm/meson/meson_plane.c +++ b/drivers/gpu/drm/meson/meson_plane.c @@ -90,6 +90,7 @@ static void meson_plane_atomic_update(struct drm_plane *plane, .y2 = state->crtc_y + state->crtc_h, }; unsigned long flags; + u8 canvas_id_osd1; /* * Update Coordinates @@ -104,8 +105,13 @@ static void meson_plane_atomic_update(struct drm_plane *plane, (0xFF << OSD_GLOBAL_ALPHA_SHIFT) | OSD_BLK0_ENABLE; + if (priv->canvas) + canvas_id_osd1 = priv->canvas_id_osd1; + else + canvas_id_osd1 = MESON_CANVAS_ID_OSD1; + /* Set up BLK0 to point to the right canvas */ - priv->viu.osd1_blk0_cfg[0] = ((MESON_CANVAS_ID_OSD1 << OSD_CANVAS_SEL) | + priv->viu.osd1_blk0_cfg[0] = ((canvas_id_osd1 << OSD_CANVAS_SEL) | OSD_ENDIANNESS_LE); /* On GXBB, Use the old non-HDR RGB2YUV converter */ -- cgit v1.2.3 From 9ef60bd673d1cd5bab882e0997cadc223670a801 Mon Sep 17 00:00:00 2001 From: YueHaibing Date: Sat, 10 Nov 2018 02:57:40 +0000 Subject: drm/sti: remove set but not used variable 'priv' Fixes gcc '-Wunused-but-set-variable' warning: drivers/gpu/drm/sti/sti_crtc.c: In function 'sti_crtc_vblank_cb': drivers/gpu/drm/sti/sti_crtc.c:255:22: warning: variable 'priv' set but not used [-Wunused-but-set-variable] It never used since introduction in commit 9e1f05b28009 ("drm/sti: rename files and functions") Signed-off-by: YueHaibing Signed-off-by: Benjamin Gaignard Link: https://patchwork.freedesktop.org/patch/msgid/1541818660-37168-1-git-send-email-yuehaibing@huawei.com --- drivers/gpu/drm/sti/sti_crtc.c | 2 -- 1 file changed, 2 deletions(-) (limited to 'drivers/gpu/drm') diff --git a/drivers/gpu/drm/sti/sti_crtc.c b/drivers/gpu/drm/sti/sti_crtc.c index 61c2379fba87..ed76e52eb213 100644 --- a/drivers/gpu/drm/sti/sti_crtc.c +++ b/drivers/gpu/drm/sti/sti_crtc.c @@ -252,10 +252,8 @@ int sti_crtc_vblank_cb(struct notifier_block *nb, struct sti_compositor *compo; struct drm_crtc *crtc = data; struct sti_mixer *mixer; - struct sti_private *priv; unsigned int pipe; - priv = crtc->dev->dev_private; pipe = drm_crtc_index(crtc); compo = container_of(nb, struct sti_compositor, vtg_vblank_nb[pipe]); mixer = compo->mixer[pipe]; -- cgit v1.2.3 From f9a2348196d1ab92e155bdba705db95d8177e886 Mon Sep 17 00:00:00 2001 From: Neil Armstrong Date: Tue, 6 Nov 2018 10:40:00 +0100 Subject: drm/meson: Support Overlay plane for video rendering The Amlogic Meson GX SoCs support an Overlay plane behind the primary plane for video rendering. This Overlay plane support various YUV layouts : - YUYV - NV12 / NV21 - YUV444 / 422 / 420 / 411 / 410 The scaler supports a wide range of scaling ratios, but for simplicity, plane atomic check limits the scaling from x5 to /5 in vertical and horizontal scaling. The z-order is fixed and always behind the primary plane and cannot be changed. The scaling parameter algorithm was taken from the Amlogic vendor kernel code and rewritten to match the atomic universal plane requirements. The video rendering using this overlay plane support has been tested using the new Kodi DRM-KMS Prime rendering path along the in-review V4L2 Mem2Mem Hardware Video Decoder up to 3840x2160 NV12 frames on various display modes. Signed-off-by: Neil Armstrong Acked-by: Daniel Vetter Tested-by: Maxime Jourdan Link: https://patchwork.freedesktop.org/patch/msgid/1541497202-20570-2-git-send-email-narmstrong@baylibre.com --- drivers/gpu/drm/meson/Makefile | 2 +- drivers/gpu/drm/meson/meson_canvas.c | 7 +- drivers/gpu/drm/meson/meson_canvas.h | 11 +- drivers/gpu/drm/meson/meson_crtc.c | 216 +++++++++++- drivers/gpu/drm/meson/meson_drv.c | 29 +- drivers/gpu/drm/meson/meson_drv.h | 52 +++ drivers/gpu/drm/meson/meson_overlay.c | 586 ++++++++++++++++++++++++++++++++ drivers/gpu/drm/meson/meson_overlay.h | 14 + drivers/gpu/drm/meson/meson_registers.h | 3 + drivers/gpu/drm/meson/meson_viu.c | 15 + drivers/gpu/drm/meson/meson_vpp.c | 44 ++- 11 files changed, 971 insertions(+), 8 deletions(-) create mode 100644 drivers/gpu/drm/meson/meson_overlay.c create mode 100644 drivers/gpu/drm/meson/meson_overlay.h (limited to 'drivers/gpu/drm') diff --git a/drivers/gpu/drm/meson/Makefile b/drivers/gpu/drm/meson/Makefile index c5c4cc362f02..7709f2fbb9f7 100644 --- a/drivers/gpu/drm/meson/Makefile +++ b/drivers/gpu/drm/meson/Makefile @@ -1,5 +1,5 @@ meson-drm-y := meson_drv.o meson_plane.o meson_crtc.o meson_venc_cvbs.o -meson-drm-y += meson_viu.o meson_vpp.o meson_venc.o meson_vclk.o meson_canvas.o +meson-drm-y += meson_viu.o meson_vpp.o meson_venc.o meson_vclk.o meson_canvas.o meson_overlay.o obj-$(CONFIG_DRM_MESON) += meson-drm.o obj-$(CONFIG_DRM_MESON_DW_HDMI) += meson_dw_hdmi.o diff --git a/drivers/gpu/drm/meson/meson_canvas.c b/drivers/gpu/drm/meson/meson_canvas.c index 08f6073d967e..5de11aa7c775 100644 --- a/drivers/gpu/drm/meson/meson_canvas.c +++ b/drivers/gpu/drm/meson/meson_canvas.c @@ -39,6 +39,7 @@ #define CANVAS_WIDTH_HBIT 0 #define CANVAS_HEIGHT_BIT 9 #define CANVAS_BLKMODE_BIT 24 +#define CANVAS_ENDIAN_BIT 26 #define DMC_CAV_LUT_ADDR 0x50 /* 0x14 offset in data sheet */ #define CANVAS_LUT_WR_EN (0x2 << 8) #define CANVAS_LUT_RD_EN (0x1 << 8) @@ -47,7 +48,8 @@ void meson_canvas_setup(struct meson_drm *priv, uint32_t canvas_index, uint32_t addr, uint32_t stride, uint32_t height, unsigned int wrap, - unsigned int blkmode) + unsigned int blkmode, + unsigned int endian) { unsigned int val; @@ -60,7 +62,8 @@ void meson_canvas_setup(struct meson_drm *priv, CANVAS_WIDTH_HBIT) | (height << CANVAS_HEIGHT_BIT) | (wrap << 22) | - (blkmode << CANVAS_BLKMODE_BIT)); + (blkmode << CANVAS_BLKMODE_BIT) | + (endian << CANVAS_ENDIAN_BIT)); regmap_write(priv->dmc, DMC_CAV_LUT_ADDR, CANVAS_LUT_WR_EN | canvas_index); diff --git a/drivers/gpu/drm/meson/meson_canvas.h b/drivers/gpu/drm/meson/meson_canvas.h index af1759da4b27..85dbf26e2826 100644 --- a/drivers/gpu/drm/meson/meson_canvas.h +++ b/drivers/gpu/drm/meson/meson_canvas.h @@ -23,6 +23,9 @@ #define __MESON_CANVAS_H #define MESON_CANVAS_ID_OSD1 0x4e +#define MESON_CANVAS_ID_VD1_0 0x60 +#define MESON_CANVAS_ID_VD1_1 0x61 +#define MESON_CANVAS_ID_VD1_2 0x62 /* Canvas configuration. */ #define MESON_CANVAS_WRAP_NONE 0x00 @@ -33,10 +36,16 @@ #define MESON_CANVAS_BLKMODE_32x32 0x01 #define MESON_CANVAS_BLKMODE_64x64 0x02 +#define MESON_CANVAS_ENDIAN_SWAP16 0x1 +#define MESON_CANVAS_ENDIAN_SWAP32 0x3 +#define MESON_CANVAS_ENDIAN_SWAP64 0x7 +#define MESON_CANVAS_ENDIAN_SWAP128 0xf + void meson_canvas_setup(struct meson_drm *priv, uint32_t canvas_index, uint32_t addr, uint32_t stride, uint32_t height, unsigned int wrap, - unsigned int blkmode); + unsigned int blkmode, + unsigned int endian); #endif /* __MESON_CANVAS_H */ diff --git a/drivers/gpu/drm/meson/meson_crtc.c b/drivers/gpu/drm/meson/meson_crtc.c index b3bc0b0ee07f..38686c9945e0 100644 --- a/drivers/gpu/drm/meson/meson_crtc.c +++ b/drivers/gpu/drm/meson/meson_crtc.c @@ -25,6 +25,7 @@ #include #include #include +#include #include #include #include @@ -98,6 +99,10 @@ static void meson_crtc_atomic_enable(struct drm_crtc *crtc, writel(crtc_state->mode.hdisplay, priv->io_base + _REG(VPP_POSTBLEND_H_SIZE)); + /* VD1 Preblend vertical start/end */ + writel(FIELD_PREP(GENMASK(11, 0), 2303), + priv->io_base + _REG(VPP_PREBLEND_VD1_V_START_END)); + writel_bits_relaxed(VPP_POSTBLEND_ENABLE, VPP_POSTBLEND_ENABLE, priv->io_base + _REG(VPP_MISC)); @@ -110,11 +115,17 @@ static void meson_crtc_atomic_disable(struct drm_crtc *crtc, struct meson_crtc *meson_crtc = to_meson_crtc(crtc); struct meson_drm *priv = meson_crtc->priv; + DRM_DEBUG_DRIVER("\n"); + priv->viu.osd1_enabled = false; priv->viu.osd1_commit = false; + priv->viu.vd1_enabled = false; + priv->viu.vd1_commit = false; + /* Disable VPP Postblend */ - writel_bits_relaxed(VPP_POSTBLEND_ENABLE, 0, + writel_bits_relaxed(VPP_OSD1_POSTBLEND | VPP_VD1_POSTBLEND | + VPP_VD1_PREBLEND | VPP_POSTBLEND_ENABLE, 0, priv->io_base + _REG(VPP_MISC)); if (crtc->state->event && !crtc->state->active) { @@ -149,6 +160,7 @@ static void meson_crtc_atomic_flush(struct drm_crtc *crtc, struct meson_drm *priv = meson_crtc->priv; priv->viu.osd1_commit = true; + priv->viu.vd1_commit = true; } static const struct drm_crtc_helper_funcs meson_crtc_helper_funcs = { @@ -202,7 +214,7 @@ void meson_crtc_irq(struct meson_drm *priv) meson_canvas_setup(priv, MESON_CANVAS_ID_OSD1, priv->viu.osd1_addr, priv->viu.osd1_stride, priv->viu.osd1_height, MESON_CANVAS_WRAP_NONE, - MESON_CANVAS_BLKMODE_LINEAR); + MESON_CANVAS_BLKMODE_LINEAR, 0); /* Enable OSD1 */ writel_bits_relaxed(VPP_OSD1_POSTBLEND, VPP_OSD1_POSTBLEND, @@ -211,6 +223,206 @@ void meson_crtc_irq(struct meson_drm *priv) priv->viu.osd1_commit = false; } + /* Update the VD1 registers */ + if (priv->viu.vd1_enabled && priv->viu.vd1_commit) { + + switch (priv->viu.vd1_planes) { + case 3: + if (priv->canvas) + meson_canvas_config(priv->canvas, + priv->canvas_id_vd1_2, + priv->viu.vd1_addr2, + priv->viu.vd1_stride2, + priv->viu.vd1_height2, + MESON_CANVAS_WRAP_NONE, + MESON_CANVAS_BLKMODE_LINEAR, + MESON_CANVAS_ENDIAN_SWAP64); + else + meson_canvas_setup(priv, MESON_CANVAS_ID_VD1_2, + priv->viu.vd1_addr2, + priv->viu.vd1_stride2, + priv->viu.vd1_height2, + MESON_CANVAS_WRAP_NONE, + MESON_CANVAS_BLKMODE_LINEAR, + MESON_CANVAS_ENDIAN_SWAP64); + /* fallthrough */ + case 2: + if (priv->canvas) + meson_canvas_config(priv->canvas, + priv->canvas_id_vd1_1, + priv->viu.vd1_addr1, + priv->viu.vd1_stride1, + priv->viu.vd1_height1, + MESON_CANVAS_WRAP_NONE, + MESON_CANVAS_BLKMODE_LINEAR, + MESON_CANVAS_ENDIAN_SWAP64); + else + meson_canvas_setup(priv, MESON_CANVAS_ID_VD1_1, + priv->viu.vd1_addr2, + priv->viu.vd1_stride2, + priv->viu.vd1_height2, + MESON_CANVAS_WRAP_NONE, + MESON_CANVAS_BLKMODE_LINEAR, + MESON_CANVAS_ENDIAN_SWAP64); + /* fallthrough */ + case 1: + if (priv->canvas) + meson_canvas_config(priv->canvas, + priv->canvas_id_vd1_0, + priv->viu.vd1_addr0, + priv->viu.vd1_stride0, + priv->viu.vd1_height0, + MESON_CANVAS_WRAP_NONE, + MESON_CANVAS_BLKMODE_LINEAR, + MESON_CANVAS_ENDIAN_SWAP64); + else + meson_canvas_setup(priv, MESON_CANVAS_ID_VD1_0, + priv->viu.vd1_addr2, + priv->viu.vd1_stride2, + priv->viu.vd1_height2, + MESON_CANVAS_WRAP_NONE, + MESON_CANVAS_BLKMODE_LINEAR, + MESON_CANVAS_ENDIAN_SWAP64); + }; + + writel_relaxed(priv->viu.vd1_if0_gen_reg, + priv->io_base + _REG(VD1_IF0_GEN_REG)); + writel_relaxed(priv->viu.vd1_if0_gen_reg, + priv->io_base + _REG(VD2_IF0_GEN_REG)); + writel_relaxed(priv->viu.vd1_if0_gen_reg2, + priv->io_base + _REG(VD1_IF0_GEN_REG2)); + writel_relaxed(priv->viu.viu_vd1_fmt_ctrl, + priv->io_base + _REG(VIU_VD1_FMT_CTRL)); + writel_relaxed(priv->viu.viu_vd1_fmt_ctrl, + priv->io_base + _REG(VIU_VD2_FMT_CTRL)); + writel_relaxed(priv->viu.viu_vd1_fmt_w, + priv->io_base + _REG(VIU_VD1_FMT_W)); + writel_relaxed(priv->viu.viu_vd1_fmt_w, + priv->io_base + _REG(VIU_VD2_FMT_W)); + writel_relaxed(priv->viu.vd1_if0_canvas0, + priv->io_base + _REG(VD1_IF0_CANVAS0)); + writel_relaxed(priv->viu.vd1_if0_canvas0, + priv->io_base + _REG(VD1_IF0_CANVAS1)); + writel_relaxed(priv->viu.vd1_if0_canvas0, + priv->io_base + _REG(VD2_IF0_CANVAS0)); + writel_relaxed(priv->viu.vd1_if0_canvas0, + priv->io_base + _REG(VD2_IF0_CANVAS1)); + writel_relaxed(priv->viu.vd1_if0_luma_x0, + priv->io_base + _REG(VD1_IF0_LUMA_X0)); + writel_relaxed(priv->viu.vd1_if0_luma_x0, + priv->io_base + _REG(VD1_IF0_LUMA_X1)); + writel_relaxed(priv->viu.vd1_if0_luma_x0, + priv->io_base + _REG(VD2_IF0_LUMA_X0)); + writel_relaxed(priv->viu.vd1_if0_luma_x0, + priv->io_base + _REG(VD2_IF0_LUMA_X1)); + writel_relaxed(priv->viu.vd1_if0_luma_y0, + priv->io_base + _REG(VD1_IF0_LUMA_Y0)); + writel_relaxed(priv->viu.vd1_if0_luma_y0, + priv->io_base + _REG(VD1_IF0_LUMA_Y1)); + writel_relaxed(priv->viu.vd1_if0_luma_y0, + priv->io_base + _REG(VD2_IF0_LUMA_Y0)); + writel_relaxed(priv->viu.vd1_if0_luma_y0, + priv->io_base + _REG(VD2_IF0_LUMA_Y1)); + writel_relaxed(priv->viu.vd1_if0_chroma_x0, + priv->io_base + _REG(VD1_IF0_CHROMA_X0)); + writel_relaxed(priv->viu.vd1_if0_chroma_x0, + priv->io_base + _REG(VD1_IF0_CHROMA_X1)); + writel_relaxed(priv->viu.vd1_if0_chroma_x0, + priv->io_base + _REG(VD2_IF0_CHROMA_X0)); + writel_relaxed(priv->viu.vd1_if0_chroma_x0, + priv->io_base + _REG(VD2_IF0_CHROMA_X1)); + writel_relaxed(priv->viu.vd1_if0_chroma_y0, + priv->io_base + _REG(VD1_IF0_CHROMA_Y0)); + writel_relaxed(priv->viu.vd1_if0_chroma_y0, + priv->io_base + _REG(VD1_IF0_CHROMA_Y1)); + writel_relaxed(priv->viu.vd1_if0_chroma_y0, + priv->io_base + _REG(VD2_IF0_CHROMA_Y0)); + writel_relaxed(priv->viu.vd1_if0_chroma_y0, + priv->io_base + _REG(VD2_IF0_CHROMA_Y1)); + writel_relaxed(priv->viu.vd1_if0_repeat_loop, + priv->io_base + _REG(VD1_IF0_RPT_LOOP)); + writel_relaxed(priv->viu.vd1_if0_repeat_loop, + priv->io_base + _REG(VD2_IF0_RPT_LOOP)); + writel_relaxed(priv->viu.vd1_if0_luma0_rpt_pat, + priv->io_base + _REG(VD1_IF0_LUMA0_RPT_PAT)); + writel_relaxed(priv->viu.vd1_if0_luma0_rpt_pat, + priv->io_base + _REG(VD2_IF0_LUMA0_RPT_PAT)); + writel_relaxed(priv->viu.vd1_if0_luma0_rpt_pat, + priv->io_base + _REG(VD1_IF0_LUMA1_RPT_PAT)); + writel_relaxed(priv->viu.vd1_if0_luma0_rpt_pat, + priv->io_base + _REG(VD2_IF0_LUMA1_RPT_PAT)); + writel_relaxed(priv->viu.vd1_if0_chroma0_rpt_pat, + priv->io_base + _REG(VD1_IF0_CHROMA0_RPT_PAT)); + writel_relaxed(priv->viu.vd1_if0_chroma0_rpt_pat, + priv->io_base + _REG(VD2_IF0_CHROMA0_RPT_PAT)); + writel_relaxed(priv->viu.vd1_if0_chroma0_rpt_pat, + priv->io_base + _REG(VD1_IF0_CHROMA1_RPT_PAT)); + writel_relaxed(priv->viu.vd1_if0_chroma0_rpt_pat, + priv->io_base + _REG(VD2_IF0_CHROMA1_RPT_PAT)); + writel_relaxed(0, priv->io_base + _REG(VD1_IF0_LUMA_PSEL)); + writel_relaxed(0, priv->io_base + _REG(VD1_IF0_CHROMA_PSEL)); + writel_relaxed(0, priv->io_base + _REG(VD2_IF0_LUMA_PSEL)); + writel_relaxed(0, priv->io_base + _REG(VD2_IF0_CHROMA_PSEL)); + writel_relaxed(priv->viu.vd1_range_map_y, + priv->io_base + _REG(VD1_IF0_RANGE_MAP_Y)); + writel_relaxed(priv->viu.vd1_range_map_cb, + priv->io_base + _REG(VD1_IF0_RANGE_MAP_CB)); + writel_relaxed(priv->viu.vd1_range_map_cr, + priv->io_base + _REG(VD1_IF0_RANGE_MAP_CR)); + writel_relaxed(0x78404, + priv->io_base + _REG(VPP_SC_MISC)); + writel_relaxed(priv->viu.vpp_pic_in_height, + priv->io_base + _REG(VPP_PIC_IN_HEIGHT)); + writel_relaxed(priv->viu.vpp_postblend_vd1_h_start_end, + priv->io_base + _REG(VPP_POSTBLEND_VD1_H_START_END)); + writel_relaxed(priv->viu.vpp_blend_vd2_h_start_end, + priv->io_base + _REG(VPP_BLEND_VD2_H_START_END)); + writel_relaxed(priv->viu.vpp_postblend_vd1_v_start_end, + priv->io_base + _REG(VPP_POSTBLEND_VD1_V_START_END)); + writel_relaxed(priv->viu.vpp_blend_vd2_v_start_end, + priv->io_base + _REG(VPP_BLEND_VD2_V_START_END)); + writel_relaxed(priv->viu.vpp_hsc_region12_startp, + priv->io_base + _REG(VPP_HSC_REGION12_STARTP)); + writel_relaxed(priv->viu.vpp_hsc_region34_startp, + priv->io_base + _REG(VPP_HSC_REGION34_STARTP)); + writel_relaxed(priv->viu.vpp_hsc_region4_endp, + priv->io_base + _REG(VPP_HSC_REGION4_ENDP)); + writel_relaxed(priv->viu.vpp_hsc_start_phase_step, + priv->io_base + _REG(VPP_HSC_START_PHASE_STEP)); + writel_relaxed(priv->viu.vpp_hsc_region1_phase_slope, + priv->io_base + _REG(VPP_HSC_REGION1_PHASE_SLOPE)); + writel_relaxed(priv->viu.vpp_hsc_region3_phase_slope, + priv->io_base + _REG(VPP_HSC_REGION3_PHASE_SLOPE)); + writel_relaxed(priv->viu.vpp_line_in_length, + priv->io_base + _REG(VPP_LINE_IN_LENGTH)); + writel_relaxed(priv->viu.vpp_preblend_h_size, + priv->io_base + _REG(VPP_PREBLEND_H_SIZE)); + writel_relaxed(priv->viu.vpp_vsc_region12_startp, + priv->io_base + _REG(VPP_VSC_REGION12_STARTP)); + writel_relaxed(priv->viu.vpp_vsc_region34_startp, + priv->io_base + _REG(VPP_VSC_REGION34_STARTP)); + writel_relaxed(priv->viu.vpp_vsc_region4_endp, + priv->io_base + _REG(VPP_VSC_REGION4_ENDP)); + writel_relaxed(priv->viu.vpp_vsc_start_phase_step, + priv->io_base + _REG(VPP_VSC_START_PHASE_STEP)); + writel_relaxed(priv->viu.vpp_vsc_ini_phase, + priv->io_base + _REG(VPP_VSC_INI_PHASE)); + writel_relaxed(priv->viu.vpp_vsc_phase_ctrl, + priv->io_base + _REG(VPP_VSC_PHASE_CTRL)); + writel_relaxed(priv->viu.vpp_hsc_phase_ctrl, + priv->io_base + _REG(VPP_HSC_PHASE_CTRL)); + writel_relaxed(0x42, priv->io_base + _REG(VPP_SCALE_COEF_IDX)); + + /* Enable VD1 */ + writel_bits_relaxed(VPP_VD1_PREBLEND | VPP_VD1_POSTBLEND | + VPP_COLOR_MNG_ENABLE, + VPP_VD1_PREBLEND | VPP_VD1_POSTBLEND | + VPP_COLOR_MNG_ENABLE, + priv->io_base + _REG(VPP_MISC)); + + priv->viu.vd1_commit = false; + } + drm_crtc_handle_vblank(priv->crtc); spin_lock_irqsave(&priv->drm->event_lock, flags); diff --git a/drivers/gpu/drm/meson/meson_drv.c b/drivers/gpu/drm/meson/meson_drv.c index 3fe6edf79b5c..3ee4d4a4ecba 100644 --- a/drivers/gpu/drm/meson/meson_drv.c +++ b/drivers/gpu/drm/meson/meson_drv.c @@ -41,6 +41,7 @@ #include "meson_drv.h" #include "meson_plane.h" +#include "meson_overlay.h" #include "meson_crtc.h" #include "meson_venc_cvbs.h" @@ -213,6 +214,24 @@ static int meson_drv_bind_master(struct device *dev, bool has_components) ret = meson_canvas_alloc(priv->canvas, &priv->canvas_id_osd1); if (ret) goto free_drm; + ret = meson_canvas_alloc(priv->canvas, &priv->canvas_id_vd1_0); + if (ret) { + meson_canvas_free(priv->canvas, priv->canvas_id_osd1); + goto free_drm; + } + ret = meson_canvas_alloc(priv->canvas, &priv->canvas_id_vd1_1); + if (ret) { + meson_canvas_free(priv->canvas, priv->canvas_id_osd1); + meson_canvas_free(priv->canvas, priv->canvas_id_vd1_0); + goto free_drm; + } + ret = meson_canvas_alloc(priv->canvas, &priv->canvas_id_vd1_2); + if (ret) { + meson_canvas_free(priv->canvas, priv->canvas_id_osd1); + meson_canvas_free(priv->canvas, priv->canvas_id_vd1_0); + meson_canvas_free(priv->canvas, priv->canvas_id_vd1_1); + goto free_drm; + } } else { priv->canvas = NULL; @@ -273,6 +292,10 @@ static int meson_drv_bind_master(struct device *dev, bool has_components) if (ret) goto free_drm; + ret = meson_overlay_create(priv); + if (ret) + goto free_drm; + ret = meson_crtc_create(priv); if (ret) goto free_drm; @@ -311,8 +334,12 @@ static void meson_drv_unbind(struct device *dev) struct drm_device *drm = dev_get_drvdata(dev); struct meson_drm *priv = drm->dev_private; - if (priv->canvas) + if (priv->canvas) { meson_canvas_free(priv->canvas, priv->canvas_id_osd1); + meson_canvas_free(priv->canvas, priv->canvas_id_vd1_0); + meson_canvas_free(priv->canvas, priv->canvas_id_vd1_1); + meson_canvas_free(priv->canvas, priv->canvas_id_vd1_2); + } drm_dev_unregister(drm); drm_kms_helper_poll_fini(drm); diff --git a/drivers/gpu/drm/meson/meson_drv.h b/drivers/gpu/drm/meson/meson_drv.h index 747a996dcbdd..83e73491039a 100644 --- a/drivers/gpu/drm/meson/meson_drv.h +++ b/drivers/gpu/drm/meson/meson_drv.h @@ -34,10 +34,14 @@ struct meson_drm { struct meson_canvas *canvas; u8 canvas_id_osd1; + u8 canvas_id_vd1_0; + u8 canvas_id_vd1_1; + u8 canvas_id_vd1_2; struct drm_device *drm; struct drm_crtc *crtc; struct drm_plane *primary_plane; + struct drm_plane *overlay_plane; /* Components Data */ struct { @@ -49,6 +53,54 @@ struct meson_drm { uint32_t osd1_addr; uint32_t osd1_stride; uint32_t osd1_height; + + bool vd1_enabled; + bool vd1_commit; + unsigned int vd1_planes; + uint32_t vd1_if0_gen_reg; + uint32_t vd1_if0_luma_x0; + uint32_t vd1_if0_luma_y0; + uint32_t vd1_if0_chroma_x0; + uint32_t vd1_if0_chroma_y0; + uint32_t vd1_if0_repeat_loop; + uint32_t vd1_if0_luma0_rpt_pat; + uint32_t vd1_if0_chroma0_rpt_pat; + uint32_t vd1_range_map_y; + uint32_t vd1_range_map_cb; + uint32_t vd1_range_map_cr; + uint32_t viu_vd1_fmt_w; + uint32_t vd1_if0_canvas0; + uint32_t vd1_if0_gen_reg2; + uint32_t viu_vd1_fmt_ctrl; + uint32_t vd1_addr0; + uint32_t vd1_addr1; + uint32_t vd1_addr2; + uint32_t vd1_stride0; + uint32_t vd1_stride1; + uint32_t vd1_stride2; + uint32_t vd1_height0; + uint32_t vd1_height1; + uint32_t vd1_height2; + uint32_t vpp_pic_in_height; + uint32_t vpp_postblend_vd1_h_start_end; + uint32_t vpp_postblend_vd1_v_start_end; + uint32_t vpp_hsc_region12_startp; + uint32_t vpp_hsc_region34_startp; + uint32_t vpp_hsc_region4_endp; + uint32_t vpp_hsc_start_phase_step; + uint32_t vpp_hsc_region1_phase_slope; + uint32_t vpp_hsc_region3_phase_slope; + uint32_t vpp_line_in_length; + uint32_t vpp_preblend_h_size; + uint32_t vpp_vsc_region12_startp; + uint32_t vpp_vsc_region34_startp; + uint32_t vpp_vsc_region4_endp; + uint32_t vpp_vsc_start_phase_step; + uint32_t vpp_vsc_ini_phase; + uint32_t vpp_vsc_phase_ctrl; + uint32_t vpp_hsc_phase_ctrl; + uint32_t vpp_blend_vd2_h_start_end; + uint32_t vpp_blend_vd2_v_start_end; } viu; struct { diff --git a/drivers/gpu/drm/meson/meson_overlay.c b/drivers/gpu/drm/meson/meson_overlay.c new file mode 100644 index 000000000000..9aebc5e4b418 --- /dev/null +++ b/drivers/gpu/drm/meson/meson_overlay.c @@ -0,0 +1,586 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (C) 2018 BayLibre, SAS + * Author: Neil Armstrong + * Copyright (C) 2015 Amlogic, Inc. All rights reserved. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "meson_overlay.h" +#include "meson_vpp.h" +#include "meson_viu.h" +#include "meson_canvas.h" +#include "meson_registers.h" + +/* VD1_IF0_GEN_REG */ +#define VD_URGENT_CHROMA BIT(28) +#define VD_URGENT_LUMA BIT(27) +#define VD_HOLD_LINES(lines) FIELD_PREP(GENMASK(24, 19), lines) +#define VD_DEMUX_MODE_RGB BIT(16) +#define VD_BYTES_PER_PIXEL(val) FIELD_PREP(GENMASK(15, 14), val) +#define VD_CHRO_RPT_LASTL_CTRL BIT(6) +#define VD_LITTLE_ENDIAN BIT(4) +#define VD_SEPARATE_EN BIT(1) +#define VD_ENABLE BIT(0) + +/* VD1_IF0_CANVAS0 */ +#define CANVAS_ADDR2(addr) FIELD_PREP(GENMASK(23, 16), addr) +#define CANVAS_ADDR1(addr) FIELD_PREP(GENMASK(15, 8), addr) +#define CANVAS_ADDR0(addr) FIELD_PREP(GENMASK(7, 0), addr) + +/* VD1_IF0_LUMA_X0 VD1_IF0_CHROMA_X0 */ +#define VD_X_START(value) FIELD_PREP(GENMASK(14, 0), value) +#define VD_X_END(value) FIELD_PREP(GENMASK(30, 16), value) + +/* VD1_IF0_LUMA_Y0 VD1_IF0_CHROMA_Y0 */ +#define VD_Y_START(value) FIELD_PREP(GENMASK(12, 0), value) +#define VD_Y_END(value) FIELD_PREP(GENMASK(28, 16), value) + +/* VD1_IF0_GEN_REG2 */ +#define VD_COLOR_MAP(value) FIELD_PREP(GENMASK(1, 0), value) + +/* VIU_VD1_FMT_CTRL */ +#define VD_HORZ_Y_C_RATIO(value) FIELD_PREP(GENMASK(22, 21), value) +#define VD_HORZ_FMT_EN BIT(20) +#define VD_VERT_RPT_LINE0 BIT(16) +#define VD_VERT_INITIAL_PHASE(value) FIELD_PREP(GENMASK(11, 8), value) +#define VD_VERT_PHASE_STEP(value) FIELD_PREP(GENMASK(7, 1), value) +#define VD_VERT_FMT_EN BIT(0) + +/* VPP_POSTBLEND_VD1_H_START_END */ +#define VD_H_END(value) FIELD_PREP(GENMASK(11, 0), value) +#define VD_H_START(value) FIELD_PREP(GENMASK(27, 16), value) + +/* VPP_POSTBLEND_VD1_V_START_END */ +#define VD_V_END(value) FIELD_PREP(GENMASK(11, 0), value) +#define VD_V_START(value) FIELD_PREP(GENMASK(27, 16), value) + +/* VPP_BLEND_VD2_V_START_END */ +#define VD2_V_END(value) FIELD_PREP(GENMASK(11, 0), value) +#define VD2_V_START(value) FIELD_PREP(GENMASK(27, 16), value) + +/* VIU_VD1_FMT_W */ +#define VD_V_WIDTH(value) FIELD_PREP(GENMASK(11, 0), value) +#define VD_H_WIDTH(value) FIELD_PREP(GENMASK(27, 16), value) + +/* VPP_HSC_REGION12_STARTP VPP_HSC_REGION34_STARTP */ +#define VD_REGION24_START(value) FIELD_PREP(GENMASK(11, 0), value) +#define VD_REGION13_END(value) FIELD_PREP(GENMASK(27, 16), value) + +struct meson_overlay { + struct drm_plane base; + struct meson_drm *priv; +}; +#define to_meson_overlay(x) container_of(x, struct meson_overlay, base) + +#define FRAC_16_16(mult, div) (((mult) << 16) / (div)) + +static int meson_overlay_atomic_check(struct drm_plane *plane, + struct drm_plane_state *state) +{ + struct drm_crtc_state *crtc_state; + + if (!state->crtc) + return 0; + + crtc_state = drm_atomic_get_crtc_state(state->state, state->crtc); + if (IS_ERR(crtc_state)) + return PTR_ERR(crtc_state); + + return drm_atomic_helper_check_plane_state(state, crtc_state, + FRAC_16_16(1, 5), + FRAC_16_16(5, 1), + true, true); +} + +/* Takes a fixed 16.16 number and converts it to integer. */ +static inline int64_t fixed16_to_int(int64_t value) +{ + return value >> 16; +} + +static const uint8_t skip_tab[6] = { + 0x24, 0x04, 0x68, 0x48, 0x28, 0x08, +}; + +static void meson_overlay_get_vertical_phase(unsigned int ratio_y, int *phase, + int *repeat, bool interlace) +{ + int offset_in = 0; + int offset_out = 0; + int repeat_skip = 0; + + if (!interlace && ratio_y > (1 << 18)) + offset_out = (1 * ratio_y) >> 10; + + while ((offset_in + (4 << 8)) <= offset_out) { + repeat_skip++; + offset_in += 4 << 8; + } + + *phase = (offset_out - offset_in) >> 2; + + if (*phase > 0x100) + repeat_skip++; + + *phase = *phase & 0xff; + + if (repeat_skip > 5) + repeat_skip = 5; + + *repeat = skip_tab[repeat_skip]; +} + +static void meson_overlay_setup_scaler_params(struct meson_drm *priv, + struct drm_plane *plane, + bool interlace_mode) +{ + struct drm_crtc_state *crtc_state = priv->crtc->state; + int video_top, video_left, video_width, video_height; + struct drm_plane_state *state = plane->state; + unsigned int vd_start_lines, vd_end_lines; + unsigned int hd_start_lines, hd_end_lines; + unsigned int crtc_height, crtc_width; + unsigned int vsc_startp, vsc_endp; + unsigned int hsc_startp, hsc_endp; + unsigned int crop_top, crop_left; + int vphase, vphase_repeat_skip; + unsigned int ratio_x, ratio_y; + int temp_height, temp_width; + unsigned int w_in, h_in; + int temp, start, end; + + if (!crtc_state) { + DRM_ERROR("Invalid crtc_state\n"); + return; + } + + crtc_height = crtc_state->mode.vdisplay; + crtc_width = crtc_state->mode.hdisplay; + + w_in = fixed16_to_int(state->src_w); + h_in = fixed16_to_int(state->src_h); + crop_top = fixed16_to_int(state->src_x); + crop_left = fixed16_to_int(state->src_x); + + video_top = state->crtc_y; + video_left = state->crtc_x; + video_width = state->crtc_w; + video_height = state->crtc_h; + + DRM_DEBUG("crtc_width %d crtc_height %d interlace %d\n", + crtc_width, crtc_height, interlace_mode); + DRM_DEBUG("w_in %d h_in %d crop_top %d crop_left %d\n", + w_in, h_in, crop_top, crop_left); + DRM_DEBUG("video top %d left %d width %d height %d\n", + video_top, video_left, video_width, video_height); + + ratio_x = (w_in << 18) / video_width; + ratio_y = (h_in << 18) / video_height; + + if (ratio_x * video_width < (w_in << 18)) + ratio_x++; + + DRM_DEBUG("ratio x 0x%x y 0x%x\n", ratio_x, ratio_y); + + meson_overlay_get_vertical_phase(ratio_y, &vphase, &vphase_repeat_skip, + interlace_mode); + + DRM_DEBUG("vphase 0x%x skip %d\n", vphase, vphase_repeat_skip); + + /* Vertical */ + + start = video_top + video_height / 2 - ((h_in << 17) / ratio_y); + end = (h_in << 18) / ratio_y + start - 1; + + if (video_top < 0 && start < 0) + vd_start_lines = (-(start) * ratio_y) >> 18; + else if (start < video_top) + vd_start_lines = ((video_top - start) * ratio_y) >> 18; + else + vd_start_lines = 0; + + if (video_top < 0) + temp_height = min_t(unsigned int, + video_top + video_height - 1, + crtc_height - 1); + else + temp_height = min_t(unsigned int, + video_top + video_height - 1, + crtc_height - 1) - video_top + 1; + + temp = vd_start_lines + (temp_height * ratio_y >> 18); + vd_end_lines = (temp <= (h_in - 1)) ? temp : (h_in - 1); + + vd_start_lines += crop_left; + vd_end_lines += crop_left; + + /* + * TOFIX: Input frames are handled and scaled like progressive frames, + * proper handling of interlaced field input frames need to be figured + * out using the proper framebuffer flags set by userspace. + */ + if (interlace_mode) { + start >>= 1; + end >>= 1; + } + + vsc_startp = max_t(int, start, + max_t(int, 0, video_top)); + vsc_endp = min_t(int, end, + min_t(int, crtc_height - 1, + video_top + video_height - 1)); + + DRM_DEBUG("vsc startp %d endp %d start_lines %d end_lines %d\n", + vsc_startp, vsc_endp, vd_start_lines, vd_end_lines); + + /* Horizontal */ + + start = video_left + video_width / 2 - ((w_in << 17) / ratio_x); + end = (w_in << 18) / ratio_x + start - 1; + + if (video_left < 0 && start < 0) + hd_start_lines = (-(start) * ratio_x) >> 18; + else if (start < video_left) + hd_start_lines = ((video_left - start) * ratio_x) >> 18; + else + hd_start_lines = 0; + + if (video_left < 0) + temp_width = min_t(unsigned int, + video_left + video_width - 1, + crtc_width - 1); + else + temp_width = min_t(unsigned int, + video_left + video_width - 1, + crtc_width - 1) - video_left + 1; + + temp = hd_start_lines + (temp_width * ratio_x >> 18); + hd_end_lines = (temp <= (w_in - 1)) ? temp : (w_in - 1); + + priv->viu.vpp_line_in_length = hd_end_lines - hd_start_lines + 1; + hsc_startp = max_t(int, start, max_t(int, 0, video_left)); + hsc_endp = min_t(int, end, min_t(int, crtc_width - 1, + video_left + video_width - 1)); + + hd_start_lines += crop_top; + hd_end_lines += crop_top; + + DRM_DEBUG("hsc startp %d endp %d start_lines %d end_lines %d\n", + hsc_startp, hsc_endp, hd_start_lines, hd_end_lines); + + priv->viu.vpp_vsc_start_phase_step = ratio_y << 6; + + priv->viu.vpp_vsc_ini_phase = vphase << 8; + priv->viu.vpp_vsc_phase_ctrl = (1 << 13) | (4 << 8) | + vphase_repeat_skip; + + priv->viu.vd1_if0_luma_x0 = VD_X_START(hd_start_lines) | + VD_X_END(hd_end_lines); + priv->viu.vd1_if0_chroma_x0 = VD_X_START(hd_start_lines >> 1) | + VD_X_END(hd_end_lines >> 1); + + priv->viu.viu_vd1_fmt_w = + VD_H_WIDTH(hd_end_lines - hd_start_lines + 1) | + VD_V_WIDTH(hd_end_lines/2 - hd_start_lines/2 + 1); + + priv->viu.vd1_if0_luma_y0 = VD_Y_START(vd_start_lines) | + VD_Y_END(vd_end_lines); + + priv->viu.vd1_if0_chroma_y0 = VD_Y_START(vd_start_lines >> 1) | + VD_Y_END(vd_end_lines >> 1); + + priv->viu.vpp_pic_in_height = h_in; + + priv->viu.vpp_postblend_vd1_h_start_end = VD_H_START(hsc_startp) | + VD_H_END(hsc_endp); + priv->viu.vpp_blend_vd2_h_start_end = VD_H_START(hd_start_lines) | + VD_H_END(hd_end_lines); + priv->viu.vpp_hsc_region12_startp = VD_REGION13_END(0) | + VD_REGION24_START(hsc_startp); + priv->viu.vpp_hsc_region34_startp = + VD_REGION13_END(hsc_startp) | + VD_REGION24_START(hsc_endp - hsc_startp); + priv->viu.vpp_hsc_region4_endp = hsc_endp - hsc_startp; + priv->viu.vpp_hsc_start_phase_step = ratio_x << 6; + priv->viu.vpp_hsc_region1_phase_slope = 0; + priv->viu.vpp_hsc_region3_phase_slope = 0; + priv->viu.vpp_hsc_phase_ctrl = (1 << 21) | (4 << 16); + + priv->viu.vpp_line_in_length = hd_end_lines - hd_start_lines + 1; + priv->viu.vpp_preblend_h_size = hd_end_lines - hd_start_lines + 1; + + priv->viu.vpp_postblend_vd1_v_start_end = VD_V_START(vsc_startp) | + VD_V_END(vsc_endp); + priv->viu.vpp_blend_vd2_v_start_end = + VD2_V_START((vd_end_lines + 1) >> 1) | + VD2_V_END(vd_end_lines); + + priv->viu.vpp_vsc_region12_startp = 0; + priv->viu.vpp_vsc_region34_startp = + VD_REGION13_END(vsc_endp - vsc_startp) | + VD_REGION24_START(vsc_endp - vsc_startp); + priv->viu.vpp_vsc_region4_endp = vsc_endp - vsc_startp; + priv->viu.vpp_vsc_start_phase_step = ratio_y << 6; +} + +static void meson_overlay_atomic_update(struct drm_plane *plane, + struct drm_plane_state *old_state) +{ + struct meson_overlay *meson_overlay = to_meson_overlay(plane); + struct drm_plane_state *state = plane->state; + struct drm_framebuffer *fb = state->fb; + struct meson_drm *priv = meson_overlay->priv; + struct drm_gem_cma_object *gem; + unsigned long flags; + bool interlace_mode; + + DRM_DEBUG_DRIVER("\n"); + + /* Fallback is canvas provider is not available */ + if (!priv->canvas) { + priv->canvas_id_vd1_0 = MESON_CANVAS_ID_VD1_0; + priv->canvas_id_vd1_1 = MESON_CANVAS_ID_VD1_1; + priv->canvas_id_vd1_2 = MESON_CANVAS_ID_VD1_2; + } + + interlace_mode = state->crtc->mode.flags & DRM_MODE_FLAG_INTERLACE; + + spin_lock_irqsave(&priv->drm->event_lock, flags); + + priv->viu.vd1_if0_gen_reg = VD_URGENT_CHROMA | + VD_URGENT_LUMA | + VD_HOLD_LINES(9) | + VD_CHRO_RPT_LASTL_CTRL | + VD_ENABLE; + + /* Setup scaler params */ + meson_overlay_setup_scaler_params(priv, plane, interlace_mode); + + priv->viu.vd1_if0_repeat_loop = 0; + priv->viu.vd1_if0_luma0_rpt_pat = interlace_mode ? 8 : 0; + priv->viu.vd1_if0_chroma0_rpt_pat = interlace_mode ? 8 : 0; + priv->viu.vd1_range_map_y = 0; + priv->viu.vd1_range_map_cb = 0; + priv->viu.vd1_range_map_cr = 0; + + /* Default values for RGB888/YUV444 */ + priv->viu.vd1_if0_gen_reg2 = 0; + priv->viu.viu_vd1_fmt_ctrl = 0; + + switch (fb->format->format) { + /* TOFIX DRM_FORMAT_RGB888 should be supported */ + case DRM_FORMAT_YUYV: + priv->viu.vd1_if0_gen_reg |= VD_BYTES_PER_PIXEL(1); + priv->viu.vd1_if0_canvas0 = + CANVAS_ADDR2(priv->canvas_id_vd1_0) | + CANVAS_ADDR1(priv->canvas_id_vd1_0) | + CANVAS_ADDR0(priv->canvas_id_vd1_0); + priv->viu.viu_vd1_fmt_ctrl = VD_HORZ_Y_C_RATIO(1) | /* /2 */ + VD_HORZ_FMT_EN | + VD_VERT_RPT_LINE0 | + VD_VERT_INITIAL_PHASE(12) | + VD_VERT_PHASE_STEP(16) | /* /2 */ + VD_VERT_FMT_EN; + break; + case DRM_FORMAT_NV12: + case DRM_FORMAT_NV21: + priv->viu.vd1_if0_gen_reg |= VD_SEPARATE_EN; + priv->viu.vd1_if0_canvas0 = + CANVAS_ADDR2(priv->canvas_id_vd1_1) | + CANVAS_ADDR1(priv->canvas_id_vd1_1) | + CANVAS_ADDR0(priv->canvas_id_vd1_0); + if (fb->format->format == DRM_FORMAT_NV12) + priv->viu.vd1_if0_gen_reg2 = VD_COLOR_MAP(1); + else + priv->viu.vd1_if0_gen_reg2 = VD_COLOR_MAP(2); + priv->viu.viu_vd1_fmt_ctrl = VD_HORZ_Y_C_RATIO(1) | /* /2 */ + VD_HORZ_FMT_EN | + VD_VERT_RPT_LINE0 | + VD_VERT_INITIAL_PHASE(12) | + VD_VERT_PHASE_STEP(8) | /* /4 */ + VD_VERT_FMT_EN; + break; + case DRM_FORMAT_YUV444: + case DRM_FORMAT_YUV422: + case DRM_FORMAT_YUV420: + case DRM_FORMAT_YUV411: + case DRM_FORMAT_YUV410: + priv->viu.vd1_if0_gen_reg |= VD_SEPARATE_EN; + priv->viu.vd1_if0_canvas0 = + CANVAS_ADDR2(priv->canvas_id_vd1_2) | + CANVAS_ADDR1(priv->canvas_id_vd1_1) | + CANVAS_ADDR0(priv->canvas_id_vd1_0); + switch (fb->format->format) { + case DRM_FORMAT_YUV422: + priv->viu.viu_vd1_fmt_ctrl = + VD_HORZ_Y_C_RATIO(1) | /* /2 */ + VD_HORZ_FMT_EN | + VD_VERT_RPT_LINE0 | + VD_VERT_INITIAL_PHASE(12) | + VD_VERT_PHASE_STEP(16) | /* /2 */ + VD_VERT_FMT_EN; + break; + case DRM_FORMAT_YUV420: + priv->viu.viu_vd1_fmt_ctrl = + VD_HORZ_Y_C_RATIO(1) | /* /2 */ + VD_HORZ_FMT_EN | + VD_VERT_RPT_LINE0 | + VD_VERT_INITIAL_PHASE(12) | + VD_VERT_PHASE_STEP(8) | /* /4 */ + VD_VERT_FMT_EN; + break; + case DRM_FORMAT_YUV411: + priv->viu.viu_vd1_fmt_ctrl = + VD_HORZ_Y_C_RATIO(2) | /* /4 */ + VD_HORZ_FMT_EN | + VD_VERT_RPT_LINE0 | + VD_VERT_INITIAL_PHASE(12) | + VD_VERT_PHASE_STEP(16) | /* /2 */ + VD_VERT_FMT_EN; + break; + case DRM_FORMAT_YUV410: + priv->viu.viu_vd1_fmt_ctrl = + VD_HORZ_Y_C_RATIO(2) | /* /4 */ + VD_HORZ_FMT_EN | + VD_VERT_RPT_LINE0 | + VD_VERT_INITIAL_PHASE(12) | + VD_VERT_PHASE_STEP(8) | /* /4 */ + VD_VERT_FMT_EN; + break; + } + break; + } + + /* Update Canvas with buffer address */ + priv->viu.vd1_planes = drm_format_num_planes(fb->format->format); + + switch (priv->viu.vd1_planes) { + case 3: + gem = drm_fb_cma_get_gem_obj(fb, 2); + priv->viu.vd1_addr2 = gem->paddr + fb->offsets[2]; + priv->viu.vd1_stride2 = fb->pitches[2]; + priv->viu.vd1_height2 = + drm_format_plane_height(fb->height, + fb->format->format, 2); + DRM_DEBUG("plane 2 addr 0x%x stride %d height %d\n", + priv->viu.vd1_addr2, + priv->viu.vd1_stride2, + priv->viu.vd1_height2); + /* fallthrough */ + case 2: + gem = drm_fb_cma_get_gem_obj(fb, 1); + priv->viu.vd1_addr1 = gem->paddr + fb->offsets[1]; + priv->viu.vd1_stride1 = fb->pitches[1]; + priv->viu.vd1_height1 = + drm_format_plane_height(fb->height, + fb->format->format, 1); + DRM_DEBUG("plane 1 addr 0x%x stride %d height %d\n", + priv->viu.vd1_addr1, + priv->viu.vd1_stride1, + priv->viu.vd1_height1); + /* fallthrough */ + case 1: + gem = drm_fb_cma_get_gem_obj(fb, 0); + priv->viu.vd1_addr0 = gem->paddr + fb->offsets[0]; + priv->viu.vd1_stride0 = fb->pitches[0]; + priv->viu.vd1_height0 = + drm_format_plane_height(fb->height, + fb->format->format, 0); + DRM_DEBUG("plane 0 addr 0x%x stride %d height %d\n", + priv->viu.vd1_addr0, + priv->viu.vd1_stride0, + priv->viu.vd1_height0); + } + + priv->viu.vd1_enabled = true; + + spin_unlock_irqrestore(&priv->drm->event_lock, flags); + + DRM_DEBUG_DRIVER("\n"); +} + +static void meson_overlay_atomic_disable(struct drm_plane *plane, + struct drm_plane_state *old_state) +{ + struct meson_overlay *meson_overlay = to_meson_overlay(plane); + struct meson_drm *priv = meson_overlay->priv; + + DRM_DEBUG_DRIVER("\n"); + + priv->viu.vd1_enabled = false; + + /* Disable VD1 */ + writel_bits_relaxed(VPP_VD1_POSTBLEND | VPP_VD1_PREBLEND, 0, + priv->io_base + _REG(VPP_MISC)); + +} + +static const struct drm_plane_helper_funcs meson_overlay_helper_funcs = { + .atomic_check = meson_overlay_atomic_check, + .atomic_disable = meson_overlay_atomic_disable, + .atomic_update = meson_overlay_atomic_update, +}; + +static const struct drm_plane_funcs meson_overlay_funcs = { + .update_plane = drm_atomic_helper_update_plane, + .disable_plane = drm_atomic_helper_disable_plane, + .destroy = drm_plane_cleanup, + .reset = drm_atomic_helper_plane_reset, + .atomic_duplicate_state = drm_atomic_helper_plane_duplicate_state, + .atomic_destroy_state = drm_atomic_helper_plane_destroy_state, +}; + +static const uint32_t supported_drm_formats[] = { + DRM_FORMAT_YUYV, + DRM_FORMAT_NV12, + DRM_FORMAT_NV21, + DRM_FORMAT_YUV444, + DRM_FORMAT_YUV422, + DRM_FORMAT_YUV420, + DRM_FORMAT_YUV411, + DRM_FORMAT_YUV410, +}; + +int meson_overlay_create(struct meson_drm *priv) +{ + struct meson_overlay *meson_overlay; + struct drm_plane *plane; + + DRM_DEBUG_DRIVER("\n"); + + meson_overlay = devm_kzalloc(priv->drm->dev, sizeof(*meson_overlay), + GFP_KERNEL); + if (!meson_overlay) + return -ENOMEM; + + meson_overlay->priv = priv; + plane = &meson_overlay->base; + + drm_universal_plane_init(priv->drm, plane, 0xFF, + &meson_overlay_funcs, + supported_drm_formats, + ARRAY_SIZE(supported_drm_formats), + NULL, + DRM_PLANE_TYPE_OVERLAY, "meson_overlay_plane"); + + drm_plane_helper_add(plane, &meson_overlay_helper_funcs); + + priv->overlay_plane = plane; + + DRM_DEBUG_DRIVER("\n"); + + return 0; +} diff --git a/drivers/gpu/drm/meson/meson_overlay.h b/drivers/gpu/drm/meson/meson_overlay.h new file mode 100644 index 000000000000..dae24f5ac63d --- /dev/null +++ b/drivers/gpu/drm/meson/meson_overlay.h @@ -0,0 +1,14 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * Copyright (C) 2018 BayLibre, SAS + * Author: Neil Armstrong + */ + +#ifndef __MESON_OVERLAY_H +#define __MESON_OVERLAY_H + +#include "meson_drv.h" + +int meson_overlay_create(struct meson_drm *priv); + +#endif /* __MESON_OVERLAY_H */ diff --git a/drivers/gpu/drm/meson/meson_registers.h b/drivers/gpu/drm/meson/meson_registers.h index bca87143e548..5c7e02c703bc 100644 --- a/drivers/gpu/drm/meson/meson_registers.h +++ b/drivers/gpu/drm/meson/meson_registers.h @@ -286,6 +286,7 @@ #define VIU_OSD1_MATRIX_COEF22_30 0x1a9d #define VIU_OSD1_MATRIX_COEF31_32 0x1a9e #define VIU_OSD1_MATRIX_COEF40_41 0x1a9f +#define VD1_IF0_GEN_REG3 0x1aa7 #define VIU_OSD1_EOTF_CTL 0x1ad4 #define VIU_OSD1_EOTF_COEF00_01 0x1ad5 #define VIU_OSD1_EOTF_COEF02_10 0x1ad6 @@ -297,6 +298,7 @@ #define VIU_OSD1_OETF_CTL 0x1adc #define VIU_OSD1_OETF_LUT_ADDR_PORT 0x1add #define VIU_OSD1_OETF_LUT_DATA_PORT 0x1ade +#define AFBC_ENABLE 0x1ae0 /* vpp */ #define VPP_DUMMY_DATA 0x1d00 @@ -349,6 +351,7 @@ #define VPP_VD2_PREBLEND BIT(15) #define VPP_OSD1_PREBLEND BIT(16) #define VPP_OSD2_PREBLEND BIT(17) +#define VPP_COLOR_MNG_ENABLE BIT(28) #define VPP_OFIFO_SIZE 0x1d27 #define VPP_FIFO_STATUS 0x1d28 #define VPP_SMOKE_CTRL 0x1d29 diff --git a/drivers/gpu/drm/meson/meson_viu.c b/drivers/gpu/drm/meson/meson_viu.c index 6bcfa527c180..2dffb987ec65 100644 --- a/drivers/gpu/drm/meson/meson_viu.c +++ b/drivers/gpu/drm/meson/meson_viu.c @@ -329,6 +329,21 @@ void meson_viu_init(struct meson_drm *priv) 0xff << OSD_REPLACE_SHIFT, priv->io_base + _REG(VIU_OSD2_CTRL_STAT2)); + /* Disable VD1 AFBC */ + /* di_mif0_en=0 mif0_to_vpp_en=0 di_mad_en=0 */ + writel_bits_relaxed(0x7 << 16, 0, + priv->io_base + _REG(VIU_MISC_CTRL0)); + /* afbc vd1 set=0 */ + writel_bits_relaxed(BIT(20), 0, + priv->io_base + _REG(VIU_MISC_CTRL0)); + writel_relaxed(0, priv->io_base + _REG(AFBC_ENABLE)); + + writel_relaxed(0x00FF00C0, + priv->io_base + _REG(VD1_IF0_LUMA_FIFO_SIZE)); + writel_relaxed(0x00FF00C0, + priv->io_base + _REG(VD2_IF0_LUMA_FIFO_SIZE)); + + priv->viu.osd1_enabled = false; priv->viu.osd1_commit = false; priv->viu.osd1_interlace = false; diff --git a/drivers/gpu/drm/meson/meson_vpp.c b/drivers/gpu/drm/meson/meson_vpp.c index 27356f81a0ab..5dc24a99e978 100644 --- a/drivers/gpu/drm/meson/meson_vpp.c +++ b/drivers/gpu/drm/meson/meson_vpp.c @@ -122,6 +122,31 @@ static void meson_vpp_write_scaling_filter_coefs(struct meson_drm *priv, priv->io_base + _REG(VPP_OSD_SCALE_COEF)); } +static const uint32_t vpp_filter_coefs_bicubic[] = { + 0x00800000, 0x007f0100, 0xff7f0200, 0xfe7f0300, + 0xfd7e0500, 0xfc7e0600, 0xfb7d0800, 0xfb7c0900, + 0xfa7b0b00, 0xfa7a0dff, 0xf9790fff, 0xf97711ff, + 0xf87613ff, 0xf87416fe, 0xf87218fe, 0xf8701afe, + 0xf76f1dfd, 0xf76d1ffd, 0xf76b21fd, 0xf76824fd, + 0xf76627fc, 0xf76429fc, 0xf7612cfc, 0xf75f2ffb, + 0xf75d31fb, 0xf75a34fb, 0xf75837fa, 0xf7553afa, + 0xf8523cfa, 0xf8503ff9, 0xf84d42f9, 0xf84a45f9, + 0xf84848f8 +}; + +static void meson_vpp_write_vd_scaling_filter_coefs(struct meson_drm *priv, + const unsigned int *coefs, + bool is_horizontal) +{ + int i; + + writel_relaxed(is_horizontal ? BIT(8) : 0, + priv->io_base + _REG(VPP_SCALE_COEF_IDX)); + for (i = 0; i < 33; i++) + writel_relaxed(coefs[i], + priv->io_base + _REG(VPP_SCALE_COEF)); +} + void meson_vpp_init(struct meson_drm *priv) { /* set dummy data default YUV black */ @@ -150,17 +175,34 @@ void meson_vpp_init(struct meson_drm *priv) /* Force all planes off */ writel_bits_relaxed(VPP_OSD1_POSTBLEND | VPP_OSD2_POSTBLEND | - VPP_VD1_POSTBLEND | VPP_VD2_POSTBLEND, 0, + VPP_VD1_POSTBLEND | VPP_VD2_POSTBLEND | + VPP_VD1_PREBLEND | VPP_VD2_PREBLEND, 0, priv->io_base + _REG(VPP_MISC)); + /* Setup default VD settings */ + writel_relaxed(4096, + priv->io_base + _REG(VPP_PREBLEND_VD1_H_START_END)); + writel_relaxed(4096, + priv->io_base + _REG(VPP_BLEND_VD2_H_START_END)); + /* Disable Scalers */ writel_relaxed(0, priv->io_base + _REG(VPP_OSD_SC_CTRL0)); writel_relaxed(0, priv->io_base + _REG(VPP_OSD_VSC_CTRL0)); writel_relaxed(0, priv->io_base + _REG(VPP_OSD_HSC_CTRL0)); + writel_relaxed(4 | (4 << 8) | BIT(15), + priv->io_base + _REG(VPP_SC_MISC)); + + writel_relaxed(1, priv->io_base + _REG(VPP_VADJ_CTRL)); /* Write in the proper filter coefficients. */ meson_vpp_write_scaling_filter_coefs(priv, vpp_filter_coefs_4point_bspline, false); meson_vpp_write_scaling_filter_coefs(priv, vpp_filter_coefs_4point_bspline, true); + + /* Write the VD proper filter coefficients. */ + meson_vpp_write_vd_scaling_filter_coefs(priv, vpp_filter_coefs_bicubic, + false); + meson_vpp_write_vd_scaling_filter_coefs(priv, vpp_filter_coefs_bicubic, + true); } -- cgit v1.2.3 From 20d7fe034a2fda304dd9a8d2eb876f0fcaaef928 Mon Sep 17 00:00:00 2001 From: Neil Armstrong Date: Tue, 6 Nov 2018 10:40:01 +0100 Subject: drm/meson: move OSD scaler management into plane atomic update In preparation to support the Primary Plane scaling, move the basic OSD Interlace-Only scaler setup code into the primary plane atomic update callback and handle the vsync scaler update like the overlay plane scaling registers update. Signed-off-by: Neil Armstrong Acked-by: Daniel Vetter Link: https://patchwork.freedesktop.org/patch/msgid/1541497202-20570-3-git-send-email-narmstrong@baylibre.com --- drivers/gpu/drm/meson/meson_crtc.c | 35 ++++++++++++++++------------ drivers/gpu/drm/meson/meson_drv.h | 10 ++++++++ drivers/gpu/drm/meson/meson_plane.c | 39 ++++++++++++++++++++++++++++++- drivers/gpu/drm/meson/meson_vpp.c | 46 ------------------------------------- 4 files changed, 68 insertions(+), 62 deletions(-) (limited to 'drivers/gpu/drm') diff --git a/drivers/gpu/drm/meson/meson_crtc.c b/drivers/gpu/drm/meson/meson_crtc.c index 38686c9945e0..d78168f979db 100644 --- a/drivers/gpu/drm/meson/meson_crtc.c +++ b/drivers/gpu/drm/meson/meson_crtc.c @@ -189,21 +189,26 @@ void meson_crtc_irq(struct meson_drm *priv) priv->io_base + _REG(VIU_OSD1_BLK0_CFG_W3)); writel_relaxed(priv->viu.osd1_blk0_cfg[4], priv->io_base + _REG(VIU_OSD1_BLK0_CFG_W4)); - - /* If output is interlace, make use of the Scaler */ - if (priv->viu.osd1_interlace) { - struct drm_plane *plane = priv->primary_plane; - struct drm_plane_state *state = plane->state; - struct drm_rect dest = { - .x1 = state->crtc_x, - .y1 = state->crtc_y, - .x2 = state->crtc_x + state->crtc_w, - .y2 = state->crtc_y + state->crtc_h, - }; - - meson_vpp_setup_interlace_vscaler_osd1(priv, &dest); - } else - meson_vpp_disable_interlace_vscaler_osd1(priv); + writel_relaxed(priv->viu.osd_sc_ctrl0, + priv->io_base + _REG(VPP_OSD_SC_CTRL0)); + writel_relaxed(priv->viu.osd_sc_i_wh_m1, + priv->io_base + _REG(VPP_OSD_SCI_WH_M1)); + writel_relaxed(priv->viu.osd_sc_o_h_start_end, + priv->io_base + _REG(VPP_OSD_SCO_H_START_END)); + writel_relaxed(priv->viu.osd_sc_o_v_start_end, + priv->io_base + _REG(VPP_OSD_SCO_V_START_END)); + writel_relaxed(priv->viu.osd_sc_v_ini_phase, + priv->io_base + _REG(VPP_OSD_VSC_INI_PHASE)); + writel_relaxed(priv->viu.osd_sc_v_phase_step, + priv->io_base + _REG(VPP_OSD_VSC_PHASE_STEP)); + writel_relaxed(priv->viu.osd_sc_h_ini_phase, + priv->io_base + _REG(VPP_OSD_HSC_INI_PHASE)); + writel_relaxed(priv->viu.osd_sc_h_phase_step, + priv->io_base + _REG(VPP_OSD_HSC_PHASE_STEP)); + writel_relaxed(priv->viu.osd_sc_h_ctrl0, + priv->io_base + _REG(VPP_OSD_HSC_CTRL0)); + writel_relaxed(priv->viu.osd_sc_v_ctrl0, + priv->io_base + _REG(VPP_OSD_VSC_CTRL0)); if (priv->canvas) meson_canvas_config(priv->canvas, priv->canvas_id_osd1, diff --git a/drivers/gpu/drm/meson/meson_drv.h b/drivers/gpu/drm/meson/meson_drv.h index 83e73491039a..4dccf4cd042a 100644 --- a/drivers/gpu/drm/meson/meson_drv.h +++ b/drivers/gpu/drm/meson/meson_drv.h @@ -53,6 +53,16 @@ struct meson_drm { uint32_t osd1_addr; uint32_t osd1_stride; uint32_t osd1_height; + uint32_t osd_sc_ctrl0; + uint32_t osd_sc_i_wh_m1; + uint32_t osd_sc_o_h_start_end; + uint32_t osd_sc_o_v_start_end; + uint32_t osd_sc_v_ini_phase; + uint32_t osd_sc_v_phase_step; + uint32_t osd_sc_h_ini_phase; + uint32_t osd_sc_h_phase_step; + uint32_t osd_sc_h_ctrl0; + uint32_t osd_sc_v_ctrl0; bool vd1_enabled; bool vd1_commit; diff --git a/drivers/gpu/drm/meson/meson_plane.c b/drivers/gpu/drm/meson/meson_plane.c index 51bec8e98a39..8712498f9e93 100644 --- a/drivers/gpu/drm/meson/meson_plane.c +++ b/drivers/gpu/drm/meson/meson_plane.c @@ -143,13 +143,50 @@ static void meson_plane_atomic_update(struct drm_plane *plane, break; }; + /* + * When the output is interlaced, the OSD must switch between + * each field using the INTERLACE_SEL_ODD (0) of VIU_OSD1_BLK0_CFG_W0 + * at each vsync. + * But the vertical scaler can provide such funtionnality if + * is configured for 2:1 scaling with interlace options enabled. + */ if (state->crtc->mode.flags & DRM_MODE_FLAG_INTERLACE) { priv->viu.osd1_interlace = true; dest.y1 /= 2; dest.y2 /= 2; - } else + + priv->viu.osd_sc_ctrl0 = BIT(3) | /* Enable scaler */ + BIT(2); /* Select OSD1 */ + + /* 2:1 scaling */ + priv->viu.osd_sc_i_wh_m1 = ((drm_rect_width(&dest) - 1) << 16) | + (drm_rect_height(&dest) - 1); + priv->viu.osd_sc_o_h_start_end = (dest.x1 << 16) | dest.x2; + priv->viu.osd_sc_o_v_start_end = (dest.y1 << 16) | dest.y2; + + /* 2:1 vertical scaling values */ + priv->viu.osd_sc_v_ini_phase = BIT(16); + priv->viu.osd_sc_v_phase_step = BIT(25); + priv->viu.osd_sc_v_ctrl0 = + (4 << 0) | /* osd_vsc_bank_length */ + (4 << 3) | /* osd_vsc_top_ini_rcv_num0 */ + (1 << 8) | /* osd_vsc_top_rpt_p0_num0 */ + (6 << 11) | /* osd_vsc_bot_ini_rcv_num0 */ + (2 << 16) | /* osd_vsc_bot_rpt_p0_num0 */ + BIT(23) | /* osd_prog_interlace */ + BIT(24); /* Enable vertical scaler */ + + /* No horizontal scaling */ + priv->viu.osd_sc_h_ini_phase = 0; + priv->viu.osd_sc_h_phase_step = 0; + priv->viu.osd_sc_h_ctrl0 = 0; + } else { priv->viu.osd1_interlace = false; + priv->viu.osd_sc_ctrl0 = 0; + priv->viu.osd_sc_h_ctrl0 = 0; + priv->viu.osd_sc_v_ctrl0 = 0; + } /* * The format of these registers is (x2 << 16 | x1), diff --git a/drivers/gpu/drm/meson/meson_vpp.c b/drivers/gpu/drm/meson/meson_vpp.c index 5dc24a99e978..f9efb431e953 100644 --- a/drivers/gpu/drm/meson/meson_vpp.c +++ b/drivers/gpu/drm/meson/meson_vpp.c @@ -51,52 +51,6 @@ void meson_vpp_setup_mux(struct meson_drm *priv, unsigned int mux) writel(mux, priv->io_base + _REG(VPU_VIU_VENC_MUX_CTRL)); } -/* - * When the output is interlaced, the OSD must switch between - * each field using the INTERLACE_SEL_ODD (0) of VIU_OSD1_BLK0_CFG_W0 - * at each vsync. - * But the vertical scaler can provide such funtionnality if - * is configured for 2:1 scaling with interlace options enabled. - */ -void meson_vpp_setup_interlace_vscaler_osd1(struct meson_drm *priv, - struct drm_rect *input) -{ - writel_relaxed(BIT(3) /* Enable scaler */ | - BIT(2), /* Select OSD1 */ - priv->io_base + _REG(VPP_OSD_SC_CTRL0)); - - writel_relaxed(((drm_rect_width(input) - 1) << 16) | - (drm_rect_height(input) - 1), - priv->io_base + _REG(VPP_OSD_SCI_WH_M1)); - /* 2:1 scaling */ - writel_relaxed(((input->x1) << 16) | (input->x2), - priv->io_base + _REG(VPP_OSD_SCO_H_START_END)); - writel_relaxed(((input->y1 >> 1) << 16) | (input->y2 >> 1), - priv->io_base + _REG(VPP_OSD_SCO_V_START_END)); - - /* 2:1 scaling values */ - writel_relaxed(BIT(16), priv->io_base + _REG(VPP_OSD_VSC_INI_PHASE)); - writel_relaxed(BIT(25), priv->io_base + _REG(VPP_OSD_VSC_PHASE_STEP)); - - writel_relaxed(0, priv->io_base + _REG(VPP_OSD_HSC_CTRL0)); - - writel_relaxed((4 << 0) /* osd_vsc_bank_length */ | - (4 << 3) /* osd_vsc_top_ini_rcv_num0 */ | - (1 << 8) /* osd_vsc_top_rpt_p0_num0 */ | - (6 << 11) /* osd_vsc_bot_ini_rcv_num0 */ | - (2 << 16) /* osd_vsc_bot_rpt_p0_num0 */ | - BIT(23) /* osd_prog_interlace */ | - BIT(24), /* Enable vertical scaler */ - priv->io_base + _REG(VPP_OSD_VSC_CTRL0)); -} - -void meson_vpp_disable_interlace_vscaler_osd1(struct meson_drm *priv) -{ - writel_relaxed(0, priv->io_base + _REG(VPP_OSD_SC_CTRL0)); - writel_relaxed(0, priv->io_base + _REG(VPP_OSD_VSC_CTRL0)); - writel_relaxed(0, priv->io_base + _REG(VPP_OSD_HSC_CTRL0)); -} - static unsigned int vpp_filter_coefs_4point_bspline[] = { 0x15561500, 0x14561600, 0x13561700, 0x12561800, 0x11551a00, 0x11541b00, 0x10541c00, 0x0f541d00, -- cgit v1.2.3 From 7db647aa8b134059c3b8f26b1dd2e1aa5b91e2ca Mon Sep 17 00:00:00 2001 From: Neil Armstrong Date: Tue, 6 Nov 2018 10:40:02 +0100 Subject: drm/meson: Add primary plane scaling This patch adds support for the Primary Plane scaling. On the Amlogic GX SoCs, the primary plane is used as On-Screen-Display layer on top of video, and it's needed to keep the OSD layer to a lower size as the physical display size to : - lower the memory bandwidth - lower the OSD rendering - lower the memory usage This use-case is used when setting the display mode to 3840x2160 and the OSD layer is rendered using the GPU. In this case, the GXBB & GXL cannot work on more than 2000x2000 buffer, thus needing the OSD layer to be kept at 1920x1080 and upscaled to 3840x2160 in hardware. The primary plane atomic check still allow 1:1 scaling, allowing native 3840x2160 if needed by user-space applications. Signed-off-by: Neil Armstrong Acked-by: Daniel Vetter [narmstrong: fixed apply from malformed patch] Link: https://patchwork.freedesktop.org/patch/msgid/1541497202-20570-4-git-send-email-narmstrong@baylibre.com --- drivers/gpu/drm/meson/meson_plane.c | 186 +++++++++++++++++++++++++++--------- 1 file changed, 141 insertions(+), 45 deletions(-) (limited to 'drivers/gpu/drm') diff --git a/drivers/gpu/drm/meson/meson_plane.c b/drivers/gpu/drm/meson/meson_plane.c index 8712498f9e93..12a47b4f65a5 100644 --- a/drivers/gpu/drm/meson/meson_plane.c +++ b/drivers/gpu/drm/meson/meson_plane.c @@ -24,6 +24,7 @@ #include #include #include +#include #include #include #include @@ -39,12 +40,50 @@ #include "meson_canvas.h" #include "meson_registers.h" +/* OSD_SCI_WH_M1 */ +#define SCI_WH_M1_W(w) FIELD_PREP(GENMASK(28, 16), w) +#define SCI_WH_M1_H(h) FIELD_PREP(GENMASK(12, 0), h) + +/* OSD_SCO_H_START_END */ +/* OSD_SCO_V_START_END */ +#define SCO_HV_START(start) FIELD_PREP(GENMASK(27, 16), start) +#define SCO_HV_END(end) FIELD_PREP(GENMASK(11, 0), end) + +/* OSD_SC_CTRL0 */ +#define SC_CTRL0_PATH_EN BIT(3) +#define SC_CTRL0_SEL_OSD1 BIT(2) + +/* OSD_VSC_CTRL0 */ +#define VSC_BANK_LEN(value) FIELD_PREP(GENMASK(2, 0), value) +#define VSC_TOP_INI_RCV_NUM(value) FIELD_PREP(GENMASK(6, 3), value) +#define VSC_TOP_RPT_L0_NUM(value) FIELD_PREP(GENMASK(9, 8), value) +#define VSC_BOT_INI_RCV_NUM(value) FIELD_PREP(GENMASK(14, 11), value) +#define VSC_BOT_RPT_L0_NUM(value) FIELD_PREP(GENMASK(17, 16), value) +#define VSC_PROG_INTERLACE BIT(23) +#define VSC_VERTICAL_SCALER_EN BIT(24) + +/* OSD_VSC_INI_PHASE */ +#define VSC_INI_PHASE_BOT(bottom) FIELD_PREP(GENMASK(31, 16), bottom) +#define VSC_INI_PHASE_TOP(top) FIELD_PREP(GENMASK(15, 0), top) + +/* OSD_HSC_CTRL0 */ +#define HSC_BANK_LENGTH(value) FIELD_PREP(GENMASK(2, 0), value) +#define HSC_INI_RCV_NUM0(value) FIELD_PREP(GENMASK(6, 3), value) +#define HSC_RPT_P0_NUM0(value) FIELD_PREP(GENMASK(9, 8), value) +#define HSC_HORIZ_SCALER_EN BIT(22) + +/* VPP_OSD_VSC_PHASE_STEP */ +/* VPP_OSD_HSC_PHASE_STEP */ +#define SC_PHASE_STEP(value) FIELD_PREP(GENMASK(27, 0), value) + struct meson_plane { struct drm_plane base; struct meson_drm *priv; }; #define to_meson_plane(x) container_of(x, struct meson_plane, base) +#define FRAC_16_16(mult, div) (((mult) << 16) / (div)) + static int meson_plane_atomic_check(struct drm_plane *plane, struct drm_plane_state *state) { @@ -57,10 +96,15 @@ static int meson_plane_atomic_check(struct drm_plane *plane, if (IS_ERR(crtc_state)) return PTR_ERR(crtc_state); + /* + * Only allow : + * - Upscaling up to 5x, vertical and horizontal + * - Final coordinates must match crtc size + */ return drm_atomic_helper_check_plane_state(state, crtc_state, + FRAC_16_16(1, 5), DRM_PLANE_HELPER_NO_SCALING, - DRM_PLANE_HELPER_NO_SCALING, - true, true); + false, true); } /* Takes a fixed 16.16 number and converts it to integer. */ @@ -74,22 +118,19 @@ static void meson_plane_atomic_update(struct drm_plane *plane, { struct meson_plane *meson_plane = to_meson_plane(plane); struct drm_plane_state *state = plane->state; - struct drm_framebuffer *fb = state->fb; + struct drm_rect dest = drm_plane_state_dest(state); struct meson_drm *priv = meson_plane->priv; + struct drm_framebuffer *fb = state->fb; struct drm_gem_cma_object *gem; - struct drm_rect src = { - .x1 = (state->src_x), - .y1 = (state->src_y), - .x2 = (state->src_x + state->src_w), - .y2 = (state->src_y + state->src_h), - }; - struct drm_rect dest = { - .x1 = state->crtc_x, - .y1 = state->crtc_y, - .x2 = state->crtc_x + state->crtc_w, - .y2 = state->crtc_y + state->crtc_h, - }; unsigned long flags; + int vsc_ini_rcv_num, vsc_ini_rpt_p0_num; + int vsc_bot_rcv_num, vsc_bot_rpt_p0_num; + int hsc_ini_rcv_num, hsc_ini_rpt_p0_num; + int hf_phase_step, vf_phase_step; + int src_w, src_h, dst_w, dst_h; + int bot_ini_phase; + int hf_bank_len; + int vf_bank_len; u8 canvas_id_osd1; /* @@ -143,6 +184,27 @@ static void meson_plane_atomic_update(struct drm_plane *plane, break; }; + /* Default scaler parameters */ + vsc_bot_rcv_num = 0; + vsc_bot_rpt_p0_num = 0; + hf_bank_len = 4; + vf_bank_len = 4; + + if (state->crtc->mode.flags & DRM_MODE_FLAG_INTERLACE) { + vsc_bot_rcv_num = 6; + vsc_bot_rpt_p0_num = 2; + } + + hsc_ini_rcv_num = hf_bank_len; + vsc_ini_rcv_num = vf_bank_len; + hsc_ini_rpt_p0_num = (hf_bank_len / 2) - 1; + vsc_ini_rpt_p0_num = (vf_bank_len / 2) - 1; + + src_w = fixed16_to_int(state->src_w); + src_h = fixed16_to_int(state->src_h); + dst_w = state->crtc_w; + dst_h = state->crtc_h; + /* * When the output is interlaced, the OSD must switch between * each field using the INTERLACE_SEL_ODD (0) of VIU_OSD1_BLK0_CFG_W0 @@ -151,41 +213,73 @@ static void meson_plane_atomic_update(struct drm_plane *plane, * is configured for 2:1 scaling with interlace options enabled. */ if (state->crtc->mode.flags & DRM_MODE_FLAG_INTERLACE) { - priv->viu.osd1_interlace = true; - dest.y1 /= 2; dest.y2 /= 2; + dst_h /= 2; + } - priv->viu.osd_sc_ctrl0 = BIT(3) | /* Enable scaler */ - BIT(2); /* Select OSD1 */ + hf_phase_step = ((src_w << 18) / dst_w) << 6; + vf_phase_step = (src_h << 20) / dst_h; - /* 2:1 scaling */ - priv->viu.osd_sc_i_wh_m1 = ((drm_rect_width(&dest) - 1) << 16) | - (drm_rect_height(&dest) - 1); - priv->viu.osd_sc_o_h_start_end = (dest.x1 << 16) | dest.x2; - priv->viu.osd_sc_o_v_start_end = (dest.y1 << 16) | dest.y2; + if (state->crtc->mode.flags & DRM_MODE_FLAG_INTERLACE) + bot_ini_phase = ((vf_phase_step / 2) >> 4); + else + bot_ini_phase = 0; + + vf_phase_step = (vf_phase_step << 4); + + /* In interlaced mode, scaler is always active */ + if (src_h != dst_h || src_w != dst_w) { + priv->viu.osd_sc_i_wh_m1 = SCI_WH_M1_W(src_w - 1) | + SCI_WH_M1_H(src_h - 1); + priv->viu.osd_sc_o_h_start_end = SCO_HV_START(dest.x1) | + SCO_HV_END(dest.x2 - 1); + priv->viu.osd_sc_o_v_start_end = SCO_HV_START(dest.y1) | + SCO_HV_END(dest.y2 - 1); + /* Enable OSD Scaler */ + priv->viu.osd_sc_ctrl0 = SC_CTRL0_PATH_EN | SC_CTRL0_SEL_OSD1; + } else { + priv->viu.osd_sc_i_wh_m1 = 0; + priv->viu.osd_sc_o_h_start_end = 0; + priv->viu.osd_sc_o_v_start_end = 0; + priv->viu.osd_sc_ctrl0 = 0; + } - /* 2:1 vertical scaling values */ - priv->viu.osd_sc_v_ini_phase = BIT(16); - priv->viu.osd_sc_v_phase_step = BIT(25); + /* In interlaced mode, vertical scaler is always active */ + if (src_h != dst_h) { priv->viu.osd_sc_v_ctrl0 = - (4 << 0) | /* osd_vsc_bank_length */ - (4 << 3) | /* osd_vsc_top_ini_rcv_num0 */ - (1 << 8) | /* osd_vsc_top_rpt_p0_num0 */ - (6 << 11) | /* osd_vsc_bot_ini_rcv_num0 */ - (2 << 16) | /* osd_vsc_bot_rpt_p0_num0 */ - BIT(23) | /* osd_prog_interlace */ - BIT(24); /* Enable vertical scaler */ - - /* No horizontal scaling */ + VSC_BANK_LEN(vf_bank_len) | + VSC_TOP_INI_RCV_NUM(vsc_ini_rcv_num) | + VSC_TOP_RPT_L0_NUM(vsc_ini_rpt_p0_num) | + VSC_VERTICAL_SCALER_EN; + + if (state->crtc->mode.flags & DRM_MODE_FLAG_INTERLACE) + priv->viu.osd_sc_v_ctrl0 |= + VSC_BOT_INI_RCV_NUM(vsc_bot_rcv_num) | + VSC_BOT_RPT_L0_NUM(vsc_bot_rpt_p0_num) | + VSC_PROG_INTERLACE; + + priv->viu.osd_sc_v_phase_step = SC_PHASE_STEP(vf_phase_step); + priv->viu.osd_sc_v_ini_phase = VSC_INI_PHASE_BOT(bot_ini_phase); + } else { + priv->viu.osd_sc_v_ctrl0 = 0; + priv->viu.osd_sc_v_phase_step = 0; + priv->viu.osd_sc_v_ini_phase = 0; + } + + /* Horizontal scaler is only used if width does not match */ + if (src_w != dst_w) { + priv->viu.osd_sc_h_ctrl0 = + HSC_BANK_LENGTH(hf_bank_len) | + HSC_INI_RCV_NUM0(hsc_ini_rcv_num) | + HSC_RPT_P0_NUM0(hsc_ini_rpt_p0_num) | + HSC_HORIZ_SCALER_EN; + priv->viu.osd_sc_h_phase_step = SC_PHASE_STEP(hf_phase_step); priv->viu.osd_sc_h_ini_phase = 0; - priv->viu.osd_sc_h_phase_step = 0; - priv->viu.osd_sc_h_ctrl0 = 0; } else { - priv->viu.osd1_interlace = false; - priv->viu.osd_sc_ctrl0 = 0; priv->viu.osd_sc_h_ctrl0 = 0; - priv->viu.osd_sc_v_ctrl0 = 0; + priv->viu.osd_sc_h_phase_step = 0; + priv->viu.osd_sc_h_ini_phase = 0; } /* @@ -193,10 +287,12 @@ static void meson_plane_atomic_update(struct drm_plane *plane, * where x2 is exclusive. * e.g. +30x1920 would be (1919 << 16) | 30 */ - priv->viu.osd1_blk0_cfg[1] = ((fixed16_to_int(src.x2) - 1) << 16) | - fixed16_to_int(src.x1); - priv->viu.osd1_blk0_cfg[2] = ((fixed16_to_int(src.y2) - 1) << 16) | - fixed16_to_int(src.y1); + priv->viu.osd1_blk0_cfg[1] = + ((fixed16_to_int(state->src.x2) - 1) << 16) | + fixed16_to_int(state->src.x1); + priv->viu.osd1_blk0_cfg[2] = + ((fixed16_to_int(state->src.y2) - 1) << 16) | + fixed16_to_int(state->src.y1); priv->viu.osd1_blk0_cfg[3] = ((dest.x2 - 1) << 16) | dest.x1; priv->viu.osd1_blk0_cfg[4] = ((dest.y2 - 1) << 16) | dest.y1; -- cgit v1.2.3 From 556c62e85f9b97139c1b3f6f1585fcee0bc3eb6a Mon Sep 17 00:00:00 2001 From: Matthew Wilcox Date: Tue, 30 Oct 2018 09:53:51 -0700 Subject: drm/virtio: Handle error from virtio_gpu_resource_id_get ida_alloc() can return -ENOMEM in the highly unlikely case we run out of memory. The current code creates an object with an invalid ID. Signed-off-by: Matthew Wilcox Link: http://patchwork.freedesktop.org/patch/msgid/20181030165352.13065-1-willy@infradead.org Signed-off-by: Gerd Hoffmann --- drivers/gpu/drm/virtio/virtgpu_object.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) (limited to 'drivers/gpu/drm') diff --git a/drivers/gpu/drm/virtio/virtgpu_object.c b/drivers/gpu/drm/virtio/virtgpu_object.c index 77eac4eb06b1..5ac42dded217 100644 --- a/drivers/gpu/drm/virtio/virtgpu_object.c +++ b/drivers/gpu/drm/virtio/virtgpu_object.c @@ -25,11 +25,16 @@ #include "virtgpu_drv.h" -static void virtio_gpu_resource_id_get(struct virtio_gpu_device *vgdev, +static int virtio_gpu_resource_id_get(struct virtio_gpu_device *vgdev, uint32_t *resid) { int handle = ida_alloc_min(&vgdev->resource_ida, 1, GFP_KERNEL); + + if (handle < 0) + return handle; + *resid = handle; + return 0; } static void virtio_gpu_resource_id_put(struct virtio_gpu_device *vgdev, uint32_t id) @@ -94,7 +99,11 @@ int virtio_gpu_object_create(struct virtio_gpu_device *vgdev, bo = kzalloc(sizeof(struct virtio_gpu_object), GFP_KERNEL); if (bo == NULL) return -ENOMEM; - virtio_gpu_resource_id_get(vgdev, &bo->hw_res_handle); + ret = virtio_gpu_resource_id_get(vgdev, &bo->hw_res_handle); + if (ret < 0) { + kfree(bo); + return ret; + } size = roundup(size, PAGE_SIZE); ret = drm_gem_object_init(vgdev->ddev, &bo->gem_base, size); if (ret != 0) { -- cgit v1.2.3 From 2ae7f165c0b022a8ed1732f8ab2c11b2c173146e Mon Sep 17 00:00:00 2001 From: Matthew Wilcox Date: Tue, 30 Oct 2018 09:53:52 -0700 Subject: drm/virtio: Use IDAs more efficiently 0-based IDAs are more efficient than any other base. Convert the 1-based IDAs to be 0-based. Signed-off-by: Matthew Wilcox Link: http://patchwork.freedesktop.org/patch/msgid/20181030165352.13065-2-willy@infradead.org Signed-off-by: Gerd Hoffmann --- drivers/gpu/drm/virtio/virtgpu_kms.c | 5 +++-- drivers/gpu/drm/virtio/virtgpu_object.c | 6 +++--- 2 files changed, 6 insertions(+), 5 deletions(-) (limited to 'drivers/gpu/drm') diff --git a/drivers/gpu/drm/virtio/virtgpu_kms.c b/drivers/gpu/drm/virtio/virtgpu_kms.c index bf609dcae224..8118f10fde4a 100644 --- a/drivers/gpu/drm/virtio/virtgpu_kms.c +++ b/drivers/gpu/drm/virtio/virtgpu_kms.c @@ -55,10 +55,11 @@ static void virtio_gpu_config_changed_work_func(struct work_struct *work) static int virtio_gpu_context_create(struct virtio_gpu_device *vgdev, uint32_t nlen, const char *name) { - int handle = ida_alloc_min(&vgdev->ctx_id_ida, 1, GFP_KERNEL); + int handle = ida_alloc(&vgdev->ctx_id_ida, GFP_KERNEL); if (handle < 0) return handle; + handle += 1; virtio_gpu_cmd_context_create(vgdev, handle, nlen, name); return handle; } @@ -67,7 +68,7 @@ static void virtio_gpu_context_destroy(struct virtio_gpu_device *vgdev, uint32_t ctx_id) { virtio_gpu_cmd_context_destroy(vgdev, ctx_id); - ida_free(&vgdev->ctx_id_ida, ctx_id); + ida_free(&vgdev->ctx_id_ida, ctx_id - 1); } static void virtio_gpu_init_vq(struct virtio_gpu_queue *vgvq, diff --git a/drivers/gpu/drm/virtio/virtgpu_object.c b/drivers/gpu/drm/virtio/virtgpu_object.c index 5ac42dded217..f39a183d59c2 100644 --- a/drivers/gpu/drm/virtio/virtgpu_object.c +++ b/drivers/gpu/drm/virtio/virtgpu_object.c @@ -28,18 +28,18 @@ static int virtio_gpu_resource_id_get(struct virtio_gpu_device *vgdev, uint32_t *resid) { - int handle = ida_alloc_min(&vgdev->resource_ida, 1, GFP_KERNEL); + int handle = ida_alloc(&vgdev->resource_ida, GFP_KERNEL); if (handle < 0) return handle; - *resid = handle; + *resid = handle + 1; return 0; } static void virtio_gpu_resource_id_put(struct virtio_gpu_device *vgdev, uint32_t id) { - ida_free(&vgdev->resource_ida, id); + ida_free(&vgdev->resource_ida, id - 1); } static void virtio_gpu_ttm_bo_destroy(struct ttm_buffer_object *tbo) -- cgit v1.2.3 From 9fdd90c0f42440b7f1e4a3f7262d222eee4b4cdf Mon Sep 17 00:00:00 2001 From: Robert Foss Date: Mon, 12 Nov 2018 17:51:54 +0100 Subject: drm/virtio: add virtio_gpu_alloc_fence() Refactor fence creation, add fences to relevant GPU operations and add cursor helper functions. This removes the potential for allocation failures from the cmd_submit and atomic_commit paths. Now a fence will be allocated first and only after that will we proceed with the rest of the execution. Signed-off-by: Gustavo Padovan Signed-off-by: Robert Foss Link: http://patchwork.freedesktop.org/patch/msgid/20181112165157.32765-2-robert.foss@collabora.com Suggested-by: Rob Herring Signed-off-by: Gerd Hoffmann --- drivers/gpu/drm/virtio/virtgpu_drv.h | 4 +++ drivers/gpu/drm/virtio/virtgpu_fence.c | 29 +++++++++++++++------ drivers/gpu/drm/virtio/virtgpu_ioctl.c | 30 ++++++++++++++++++++-- drivers/gpu/drm/virtio/virtgpu_plane.c | 46 ++++++++++++++++++++++++++++++---- drivers/gpu/drm/virtio/virtgpu_vq.c | 2 +- 5 files changed, 96 insertions(+), 15 deletions(-) (limited to 'drivers/gpu/drm') diff --git a/drivers/gpu/drm/virtio/virtgpu_drv.h b/drivers/gpu/drm/virtio/virtgpu_drv.h index 6474e83cbf3d..acd130c58e33 100644 --- a/drivers/gpu/drm/virtio/virtgpu_drv.h +++ b/drivers/gpu/drm/virtio/virtgpu_drv.h @@ -131,6 +131,7 @@ struct virtio_gpu_framebuffer { int x1, y1, x2, y2; /* dirty rect */ spinlock_t dirty_lock; uint32_t hw_res_handle; + struct virtio_gpu_fence *fence; }; #define to_virtio_gpu_framebuffer(x) \ container_of(x, struct virtio_gpu_framebuffer, base) @@ -349,6 +350,9 @@ void virtio_gpu_ttm_fini(struct virtio_gpu_device *vgdev); int virtio_gpu_mmap(struct file *filp, struct vm_area_struct *vma); /* virtio_gpu_fence.c */ +struct virtio_gpu_fence *virtio_gpu_fence_alloc( + struct virtio_gpu_device *vgdev); +void virtio_gpu_fence_cleanup(struct virtio_gpu_fence *fence); int virtio_gpu_fence_emit(struct virtio_gpu_device *vgdev, struct virtio_gpu_ctrl_hdr *cmd_hdr, struct virtio_gpu_fence **fence); diff --git a/drivers/gpu/drm/virtio/virtgpu_fence.c b/drivers/gpu/drm/virtio/virtgpu_fence.c index 00c742a441bf..6b5d92215cfb 100644 --- a/drivers/gpu/drm/virtio/virtgpu_fence.c +++ b/drivers/gpu/drm/virtio/virtgpu_fence.c @@ -67,6 +67,28 @@ static const struct dma_fence_ops virtio_fence_ops = { .timeline_value_str = virtio_timeline_value_str, }; +struct virtio_gpu_fence *virtio_gpu_fence_alloc(struct virtio_gpu_device *vgdev) +{ + struct virtio_gpu_fence_driver *drv = &vgdev->fence_drv; + struct virtio_gpu_fence *fence = kzalloc(sizeof(struct virtio_gpu_fence), + GFP_ATOMIC); + if (!fence) + return fence; + + fence->drv = drv; + dma_fence_init(&fence->f, &virtio_fence_ops, &drv->lock, drv->context, 0); + + return fence; +} + +void virtio_gpu_fence_cleanup(struct virtio_gpu_fence *fence) +{ + if (!fence) + return; + + dma_fence_put(&fence->f); +} + int virtio_gpu_fence_emit(struct virtio_gpu_device *vgdev, struct virtio_gpu_ctrl_hdr *cmd_hdr, struct virtio_gpu_fence **fence) @@ -74,15 +96,8 @@ int virtio_gpu_fence_emit(struct virtio_gpu_device *vgdev, struct virtio_gpu_fence_driver *drv = &vgdev->fence_drv; unsigned long irq_flags; - *fence = kmalloc(sizeof(struct virtio_gpu_fence), GFP_ATOMIC); - if ((*fence) == NULL) - return -ENOMEM; - spin_lock_irqsave(&drv->lock, irq_flags); - (*fence)->drv = drv; (*fence)->seq = ++drv->sync_seq; - dma_fence_init(&(*fence)->f, &virtio_fence_ops, &drv->lock, - drv->context, (*fence)->seq); dma_fence_get(&(*fence)->f); list_add_tail(&(*fence)->node, &drv->fences); spin_unlock_irqrestore(&drv->lock, irq_flags); diff --git a/drivers/gpu/drm/virtio/virtgpu_ioctl.c b/drivers/gpu/drm/virtio/virtgpu_ioctl.c index bc5afa4f906e..d69fc356df0a 100644 --- a/drivers/gpu/drm/virtio/virtgpu_ioctl.c +++ b/drivers/gpu/drm/virtio/virtgpu_ioctl.c @@ -168,6 +168,13 @@ static int virtio_gpu_execbuffer_ioctl(struct drm_device *dev, void *data, ret = PTR_ERR(buf); goto out_unresv; } + + fence = virtio_gpu_fence_alloc(vgdev); + if (!fence) { + kfree(buf); + ret = -ENOMEM; + goto out_unresv; + } virtio_gpu_cmd_submit(vgdev, buf, exbuf->size, vfpriv->ctx_id, &fence); @@ -283,11 +290,17 @@ static int virtio_gpu_resource_create_ioctl(struct drm_device *dev, void *data, rc_3d.nr_samples = cpu_to_le32(rc->nr_samples); rc_3d.flags = cpu_to_le32(rc->flags); + fence = virtio_gpu_fence_alloc(vgdev); + if (!fence) { + ret = -ENOMEM; + goto fail_backoff; + } + virtio_gpu_cmd_resource_create_3d(vgdev, qobj, &rc_3d, NULL); ret = virtio_gpu_object_attach(vgdev, qobj, &fence); if (ret) { - ttm_eu_backoff_reservation(&ticket, &validate_list); - goto fail_unref; + virtio_gpu_fence_cleanup(fence); + goto fail_backoff; } ttm_eu_fence_buffer_objects(&ticket, &validate_list, &fence->f); } @@ -312,6 +325,8 @@ static int virtio_gpu_resource_create_ioctl(struct drm_device *dev, void *data, dma_fence_put(&fence->f); } return 0; +fail_backoff: + ttm_eu_backoff_reservation(&ticket, &validate_list); fail_unref: if (vgdev->has_virgl_3d) { virtio_gpu_unref_list(&validate_list); @@ -374,6 +389,12 @@ static int virtio_gpu_transfer_from_host_ioctl(struct drm_device *dev, goto out_unres; convert_to_hw_box(&box, &args->box); + + fence = virtio_gpu_fence_alloc(vgdev); + if (!fence) { + ret = -ENOMEM; + goto out_unres; + } virtio_gpu_cmd_transfer_from_host_3d (vgdev, qobj->hw_res_handle, vfpriv->ctx_id, offset, args->level, @@ -423,6 +444,11 @@ static int virtio_gpu_transfer_to_host_ioctl(struct drm_device *dev, void *data, (vgdev, qobj, offset, box.w, box.h, box.x, box.y, NULL); } else { + fence = virtio_gpu_fence_alloc(vgdev); + if (!fence) { + ret = -ENOMEM; + goto out_unres; + } virtio_gpu_cmd_transfer_to_host_3d (vgdev, qobj, vfpriv ? vfpriv->ctx_id : 0, offset, diff --git a/drivers/gpu/drm/virtio/virtgpu_plane.c b/drivers/gpu/drm/virtio/virtgpu_plane.c index a9f4ae7d4483..b84ac8c25856 100644 --- a/drivers/gpu/drm/virtio/virtgpu_plane.c +++ b/drivers/gpu/drm/virtio/virtgpu_plane.c @@ -137,6 +137,41 @@ static void virtio_gpu_primary_plane_update(struct drm_plane *plane, plane->state->src_h >> 16); } +static int virtio_gpu_cursor_prepare_fb(struct drm_plane *plane, + struct drm_plane_state *new_state) +{ + struct drm_device *dev = plane->dev; + struct virtio_gpu_device *vgdev = dev->dev_private; + struct virtio_gpu_framebuffer *vgfb; + struct virtio_gpu_object *bo; + + if (!new_state->fb) + return 0; + + vgfb = to_virtio_gpu_framebuffer(new_state->fb); + bo = gem_to_virtio_gpu_obj(vgfb->base.obj[0]); + if (bo && bo->dumb && (plane->state->fb != new_state->fb)) { + vgfb->fence = virtio_gpu_fence_alloc(vgdev); + if (!vgfb->fence) + return -ENOMEM; + } + + return 0; +} + +static void virtio_gpu_cursor_cleanup_fb(struct drm_plane *plane, + struct drm_plane_state *old_state) +{ + struct virtio_gpu_framebuffer *vgfb; + + if (!plane->state->fb) + return; + + vgfb = to_virtio_gpu_framebuffer(plane->state->fb); + if (vgfb->fence) + virtio_gpu_fence_cleanup(vgfb->fence); +} + static void virtio_gpu_cursor_plane_update(struct drm_plane *plane, struct drm_plane_state *old_state) { @@ -144,7 +179,6 @@ static void virtio_gpu_cursor_plane_update(struct drm_plane *plane, struct virtio_gpu_device *vgdev = dev->dev_private; struct virtio_gpu_output *output = NULL; struct virtio_gpu_framebuffer *vgfb; - struct virtio_gpu_fence *fence = NULL; struct virtio_gpu_object *bo = NULL; uint32_t handle; int ret = 0; @@ -170,13 +204,13 @@ static void virtio_gpu_cursor_plane_update(struct drm_plane *plane, (vgdev, bo, 0, cpu_to_le32(plane->state->crtc_w), cpu_to_le32(plane->state->crtc_h), - 0, 0, &fence); + 0, 0, &vgfb->fence); ret = virtio_gpu_object_reserve(bo, false); if (!ret) { reservation_object_add_excl_fence(bo->tbo.resv, - &fence->f); - dma_fence_put(&fence->f); - fence = NULL; + &vgfb->fence->f); + dma_fence_put(&vgfb->fence->f); + vgfb->fence = NULL; virtio_gpu_object_unreserve(bo); virtio_gpu_object_wait(bo, false); } @@ -218,6 +252,8 @@ static const struct drm_plane_helper_funcs virtio_gpu_primary_helper_funcs = { }; static const struct drm_plane_helper_funcs virtio_gpu_cursor_helper_funcs = { + .prepare_fb = virtio_gpu_cursor_prepare_fb, + .cleanup_fb = virtio_gpu_cursor_cleanup_fb, .atomic_check = virtio_gpu_plane_atomic_check, .atomic_update = virtio_gpu_cursor_plane_update, }; diff --git a/drivers/gpu/drm/virtio/virtgpu_vq.c b/drivers/gpu/drm/virtio/virtgpu_vq.c index 51bef1775e47..93f2c3a51ee8 100644 --- a/drivers/gpu/drm/virtio/virtgpu_vq.c +++ b/drivers/gpu/drm/virtio/virtgpu_vq.c @@ -896,9 +896,9 @@ void virtio_gpu_object_detach(struct virtio_gpu_device *vgdev, struct virtio_gpu_object *obj) { bool use_dma_api = !virtio_has_iommu_quirk(vgdev->vdev); - struct virtio_gpu_fence *fence; if (use_dma_api && obj->mapped) { + struct virtio_gpu_fence *fence = virtio_gpu_fence_alloc(vgdev); /* detach backing and wait for the host process it ... */ virtio_gpu_cmd_resource_inval_backing(vgdev, obj->hw_res_handle, &fence); dma_fence_wait(&fence->f, true); -- cgit v1.2.3 From a56f9c868ccf56f0ab6e3e64693e6a39323bf8d8 Mon Sep 17 00:00:00 2001 From: Robert Foss Date: Mon, 12 Nov 2018 17:51:55 +0100 Subject: drm/virtio: add uapi for in and out explicit fences Add a new field called fence_fd that will be used by userspace to send in-fences to the kernel and receive out-fences created by the kernel. This uapi enables virtio to take advantage of explicit synchronization of dma-bufs. There are two new flags: * VIRTGPU_EXECBUF_FENCE_FD_IN to be used when passing an in-fence fd. * VIRTGPU_EXECBUF_FENCE_FD_OUT to be used when requesting an out-fence fd The execbuffer IOCTL is now read-write to allow the userspace to read the out-fence. On error -1 should be returned in the fence_fd field. Signed-off-by: Gustavo Padovan Signed-off-by: Robert Foss Reviewed-by: Emil Velikov Link: http://patchwork.freedesktop.org/patch/msgid/20181112165157.32765-3-robert.foss@collabora.com Signed-off-by: Gerd Hoffmann --- drivers/gpu/drm/virtio/virtgpu_ioctl.c | 5 +++++ include/uapi/drm/virtgpu_drm.h | 13 ++++++++++--- 2 files changed, 15 insertions(+), 3 deletions(-) (limited to 'drivers/gpu/drm') diff --git a/drivers/gpu/drm/virtio/virtgpu_ioctl.c b/drivers/gpu/drm/virtio/virtgpu_ioctl.c index d69fc356df0a..3d497835b0f5 100644 --- a/drivers/gpu/drm/virtio/virtgpu_ioctl.c +++ b/drivers/gpu/drm/virtio/virtgpu_ioctl.c @@ -119,6 +119,11 @@ static int virtio_gpu_execbuffer_ioctl(struct drm_device *dev, void *data, if (vgdev->has_virgl_3d == false) return -ENOSYS; + if ((exbuf->flags & ~VIRTGPU_EXECBUF_FLAGS)) + return -EINVAL; + + exbuf->fence_fd = -1; + INIT_LIST_HEAD(&validate_list); if (exbuf->num_bo_handles) { diff --git a/include/uapi/drm/virtgpu_drm.h b/include/uapi/drm/virtgpu_drm.h index 9a781f0611df..91062f4ac7c5 100644 --- a/include/uapi/drm/virtgpu_drm.h +++ b/include/uapi/drm/virtgpu_drm.h @@ -47,6 +47,13 @@ extern "C" { #define DRM_VIRTGPU_WAIT 0x08 #define DRM_VIRTGPU_GET_CAPS 0x09 +#define VIRTGPU_EXECBUF_FENCE_FD_IN 0x01 +#define VIRTGPU_EXECBUF_FENCE_FD_OUT 0x02 +#define VIRTGPU_EXECBUF_FLAGS (\ + VIRTGPU_EXECBUF_FENCE_FD_IN |\ + VIRTGPU_EXECBUF_FENCE_FD_OUT |\ + 0) + struct drm_virtgpu_map { __u64 offset; /* use for mmap system call */ __u32 handle; @@ -54,12 +61,12 @@ struct drm_virtgpu_map { }; struct drm_virtgpu_execbuffer { - __u32 flags; /* for future use */ + __u32 flags; __u32 size; __u64 command; /* void* */ __u64 bo_handles; __u32 num_bo_handles; - __u32 pad; + __s32 fence_fd; }; #define VIRTGPU_PARAM_3D_FEATURES 1 /* do we have 3D features in the hw */ @@ -137,7 +144,7 @@ struct drm_virtgpu_get_caps { DRM_IOWR(DRM_COMMAND_BASE + DRM_VIRTGPU_MAP, struct drm_virtgpu_map) #define DRM_IOCTL_VIRTGPU_EXECBUFFER \ - DRM_IOW(DRM_COMMAND_BASE + DRM_VIRTGPU_EXECBUFFER,\ + DRM_IOWR(DRM_COMMAND_BASE + DRM_VIRTGPU_EXECBUFFER,\ struct drm_virtgpu_execbuffer) #define DRM_IOCTL_VIRTGPU_GETPARAM \ -- cgit v1.2.3 From 2cd7b6f08bc4cf06d1f00f8b42720a8457861ca1 Mon Sep 17 00:00:00 2001 From: Robert Foss Date: Mon, 12 Nov 2018 17:51:56 +0100 Subject: drm/virtio: add in/out fence support for explicit synchronization When the execbuf call receives an in-fence it will get the dma_fence related to that fence fd and wait on it before submitting the draw call. On the out-fence side we get fence returned by the submitted draw call and attach it to a sync_file and send the sync_file fd to userspace. On error -1 is returned to userspace. VIRTGPU_EXECBUF_FENCE_FD_IN & VIRTGPU_EXECBUF_FENCE_FD_OUT are supported at the simultaneously and can be flagged for simultaneously. Signed-off-by: Gustavo Padovan Signed-off-by: Robert Foss Reviewed-by: Emil Velikov Link: http://patchwork.freedesktop.org/patch/msgid/20181112165157.32765-4-robert.foss@collabora.com Suggested-by: Rob Herring Reviewed-by: Emil Velikov Signed-off-by: Gerd Hoffmann --- drivers/gpu/drm/virtio/virtgpu_ioctl.c | 81 +++++++++++++++++++++++++++------- include/uapi/drm/virtgpu_drm.h | 2 +- 2 files changed, 65 insertions(+), 18 deletions(-) (limited to 'drivers/gpu/drm') diff --git a/drivers/gpu/drm/virtio/virtgpu_ioctl.c b/drivers/gpu/drm/virtio/virtgpu_ioctl.c index 3d497835b0f5..340f2513d829 100644 --- a/drivers/gpu/drm/virtio/virtgpu_ioctl.c +++ b/drivers/gpu/drm/virtio/virtgpu_ioctl.c @@ -28,6 +28,7 @@ #include #include #include +#include #include "virtgpu_drv.h" @@ -105,7 +106,7 @@ static int virtio_gpu_execbuffer_ioctl(struct drm_device *dev, void *data, struct virtio_gpu_device *vgdev = dev->dev_private; struct virtio_gpu_fpriv *vfpriv = drm_file->driver_priv; struct drm_gem_object *gobj; - struct virtio_gpu_fence *fence; + struct virtio_gpu_fence *out_fence; struct virtio_gpu_object *qobj; int ret; uint32_t *bo_handles = NULL; @@ -114,6 +115,9 @@ static int virtio_gpu_execbuffer_ioctl(struct drm_device *dev, void *data, struct ttm_validate_buffer *buflist = NULL; int i; struct ww_acquire_ctx ticket; + struct sync_file *sync_file; + int in_fence_fd = exbuf->fence_fd; + int out_fence_fd = -1; void *buf; if (vgdev->has_virgl_3d == false) @@ -124,6 +128,33 @@ static int virtio_gpu_execbuffer_ioctl(struct drm_device *dev, void *data, exbuf->fence_fd = -1; + if (exbuf->flags & VIRTGPU_EXECBUF_FENCE_FD_IN) { + struct dma_fence *in_fence; + + in_fence = sync_file_get_fence(in_fence_fd); + + if (!in_fence) + return -EINVAL; + + /* + * Wait if the fence is from a foreign context, or if the fence + * array contains any fence from a foreign context. + */ + ret = 0; + if (!dma_fence_match_context(in_fence, vgdev->fence_drv.context)) + ret = dma_fence_wait(in_fence, true); + + dma_fence_put(in_fence); + if (ret) + return ret; + } + + if (exbuf->flags & VIRTGPU_EXECBUF_FENCE_FD_OUT) { + out_fence_fd = get_unused_fd_flags(O_CLOEXEC); + if (out_fence_fd < 0) + return out_fence_fd; + } + INIT_LIST_HEAD(&validate_list); if (exbuf->num_bo_handles) { @@ -133,26 +164,22 @@ static int virtio_gpu_execbuffer_ioctl(struct drm_device *dev, void *data, sizeof(struct ttm_validate_buffer), GFP_KERNEL | __GFP_ZERO); if (!bo_handles || !buflist) { - kvfree(bo_handles); - kvfree(buflist); - return -ENOMEM; + ret = -ENOMEM; + goto out_unused_fd; } user_bo_handles = (void __user *)(uintptr_t)exbuf->bo_handles; if (copy_from_user(bo_handles, user_bo_handles, exbuf->num_bo_handles * sizeof(uint32_t))) { ret = -EFAULT; - kvfree(bo_handles); - kvfree(buflist); - return ret; + goto out_unused_fd; } for (i = 0; i < exbuf->num_bo_handles; i++) { gobj = drm_gem_object_lookup(drm_file, bo_handles[i]); if (!gobj) { - kvfree(bo_handles); - kvfree(buflist); - return -ENOENT; + ret = -ENOENT; + goto out_unused_fd; } qobj = gem_to_virtio_gpu_obj(gobj); @@ -161,6 +188,7 @@ static int virtio_gpu_execbuffer_ioctl(struct drm_device *dev, void *data, list_add(&buflist[i].head, &validate_list); } kvfree(bo_handles); + bo_handles = NULL; } ret = virtio_gpu_object_list_validate(&ticket, &validate_list); @@ -174,28 +202,47 @@ static int virtio_gpu_execbuffer_ioctl(struct drm_device *dev, void *data, goto out_unresv; } - fence = virtio_gpu_fence_alloc(vgdev); - if (!fence) { - kfree(buf); + out_fence = virtio_gpu_fence_alloc(vgdev); + if(!out_fence) { ret = -ENOMEM; - goto out_unresv; + goto out_memdup; + } + + if (out_fence_fd >= 0) { + sync_file = sync_file_create(&out_fence->f); + if (!sync_file) { + dma_fence_put(&out_fence->f); + ret = -ENOMEM; + goto out_memdup; + } + + exbuf->fence_fd = out_fence_fd; + fd_install(out_fence_fd, sync_file->file); } + virtio_gpu_cmd_submit(vgdev, buf, exbuf->size, - vfpriv->ctx_id, &fence); + vfpriv->ctx_id, &out_fence); - ttm_eu_fence_buffer_objects(&ticket, &validate_list, &fence->f); + ttm_eu_fence_buffer_objects(&ticket, &validate_list, &out_fence->f); /* fence the command bo */ virtio_gpu_unref_list(&validate_list); kvfree(buflist); - dma_fence_put(&fence->f); return 0; +out_memdup: + kfree(buf); out_unresv: ttm_eu_backoff_reservation(&ticket, &validate_list); out_free: virtio_gpu_unref_list(&validate_list); +out_unused_fd: + kvfree(bo_handles); kvfree(buflist); + + if (out_fence_fd >= 0) + put_unused_fd(out_fence_fd); + return ret; } diff --git a/include/uapi/drm/virtgpu_drm.h b/include/uapi/drm/virtgpu_drm.h index 91062f4ac7c5..f06a789f34cd 100644 --- a/include/uapi/drm/virtgpu_drm.h +++ b/include/uapi/drm/virtgpu_drm.h @@ -66,7 +66,7 @@ struct drm_virtgpu_execbuffer { __u64 command; /* void* */ __u64 bo_handles; __u32 num_bo_handles; - __s32 fence_fd; + __s32 fence_fd; /* in/out fence fd (see VIRTGPU_EXECBUF_FENCE_FD_IN/OUT) */ }; #define VIRTGPU_PARAM_3D_FEATURES 1 /* do we have 3D features in the hw */ -- cgit v1.2.3 From 6862965261a09fc459815ba38efb758fc88006df Mon Sep 17 00:00:00 2001 From: Gustavo Padovan Date: Mon, 12 Nov 2018 17:51:57 +0100 Subject: drm/virtio: bump driver version after explicit synchronization addition To reflect the (backward compatible) changes in the uabi we are bumping the driver's version. Signed-off-by: Gustavo Padovan Signed-off-by: Robert Foss Reviewed-by: Emil Velikov Link: http://patchwork.freedesktop.org/patch/msgid/20181112165157.32765-5-robert.foss@collabora.com Signed-off-by: Gerd Hoffmann --- drivers/gpu/drm/virtio/virtgpu_drv.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/gpu/drm') diff --git a/drivers/gpu/drm/virtio/virtgpu_drv.h b/drivers/gpu/drm/virtio/virtgpu_drv.h index acd130c58e33..4632bd7e1972 100644 --- a/drivers/gpu/drm/virtio/virtgpu_drv.h +++ b/drivers/gpu/drm/virtio/virtgpu_drv.h @@ -47,8 +47,8 @@ #define DRIVER_DATE "0" #define DRIVER_MAJOR 0 -#define DRIVER_MINOR 0 -#define DRIVER_PATCHLEVEL 1 +#define DRIVER_MINOR 1 +#define DRIVER_PATCHLEVEL 0 /* virtgpu_drm_bus.c */ int drm_virtio_init(struct drm_driver *driver, struct virtio_device *vdev); -- cgit v1.2.3 From 040b595a91b21b61d6e0d388394b79c85f614e7c Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Wed, 7 Nov 2018 20:31:22 +0000 Subject: drm/virtio: fix memory leak of vfpriv on error return path The allocation for vfpriv is being leaked on an error return path, fix this by kfree'ing it before returning. Detected by CoverityScan, CID#1475380 ("Resource Leak") Fixes: 6a37c49a94a9 ("drm/virtio: Handle context ID allocation errors") Signed-off-by: Colin Ian King Link: http://patchwork.freedesktop.org/patch/msgid/20181107203122.6861-1-colin.king@canonical.com Signed-off-by: Gerd Hoffmann --- drivers/gpu/drm/virtio/virtgpu_kms.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'drivers/gpu/drm') diff --git a/drivers/gpu/drm/virtio/virtgpu_kms.c b/drivers/gpu/drm/virtio/virtgpu_kms.c index 8118f10fde4a..691b842d5f3a 100644 --- a/drivers/gpu/drm/virtio/virtgpu_kms.c +++ b/drivers/gpu/drm/virtio/virtgpu_kms.c @@ -267,8 +267,10 @@ int virtio_gpu_driver_open(struct drm_device *dev, struct drm_file *file) get_task_comm(dbgname, current); id = virtio_gpu_context_create(vgdev, strlen(dbgname), dbgname); - if (id < 0) + if (id < 0) { + kfree(vfpriv); return id; + } vfpriv->ctx_id = id; file->driver_priv = vfpriv; -- cgit v1.2.3 From 45230903ecd4068b3f3fd4ea271c525048655ce8 Mon Sep 17 00:00:00 2001 From: YueHaibing Date: Sat, 10 Nov 2018 03:44:46 +0000 Subject: drm/qxl: remove set but not used variable 'map' Fixes gcc '-Wunused-but-set-variable' warning: drivers/gpu/drm/qxl/qxl_object.c: In function 'qxl_bo_kunmap_atomic_page': drivers/gpu/drm/qxl/qxl_object.c:189:21: warning: variable 'map' set but not used [-Wunused-but-set-variable] Signed-off-by: YueHaibing Link: http://patchwork.freedesktop.org/patch/msgid/1541821486-40631-1-git-send-email-yuehaibing@huawei.com Signed-off-by: Gerd Hoffmann --- drivers/gpu/drm/qxl/qxl_object.c | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) (limited to 'drivers/gpu/drm') diff --git a/drivers/gpu/drm/qxl/qxl_object.c b/drivers/gpu/drm/qxl/qxl_object.c index f67a3c535afb..b1706cb9742a 100644 --- a/drivers/gpu/drm/qxl/qxl_object.c +++ b/drivers/gpu/drm/qxl/qxl_object.c @@ -186,13 +186,9 @@ void qxl_bo_kunmap_atomic_page(struct qxl_device *qdev, struct qxl_bo *bo, void *pmap) { struct ttm_mem_type_manager *man = &bo->tbo.bdev->man[bo->tbo.mem.mem_type]; - struct io_mapping *map; - if (bo->tbo.mem.mem_type == TTM_PL_VRAM) - map = qdev->vram_mapping; - else if (bo->tbo.mem.mem_type == TTM_PL_PRIV) - map = qdev->surface_mapping; - else + if ((bo->tbo.mem.mem_type != TTM_PL_VRAM) && + (bo->tbo.mem.mem_type != TTM_PL_PRIV)) goto fallback; io_mapping_unmap_atomic(pmap); @@ -200,7 +196,7 @@ void qxl_bo_kunmap_atomic_page(struct qxl_device *qdev, (void) ttm_mem_io_lock(man, false); ttm_mem_io_free(bo->tbo.bdev, &bo->tbo.mem); ttm_mem_io_unlock(man); - return ; + return; fallback: qxl_bo_kunmap(bo); } -- cgit v1.2.3 From 55a2a982d39c051c0479277fc3a7ac8205565ed8 Mon Sep 17 00:00:00 2001 From: YueHaibing Date: Mon, 12 Nov 2018 13:32:36 +0000 Subject: drm/qxl: remove set but not used variables 'driver, qbo' Fixes gcc '-Wunused-but-set-variable' warning: drivers/gpu/drm/qxl/qxl_release.c: In function 'qxl_release_fence_buffer_objects': drivers/gpu/drm/qxl/qxl_release.c:431:17: warning: variable 'qbo' set but not used [-Wunused-but-set-variable] drivers/gpu/drm/qxl/qxl_release.c:430:24: warning: variable 'driver' set but not used [-Wunused-but-set-variable] 'qbo' not used since commit f2c24b83ae90 ("drm/ttm: flip the switch, and convert to dma_fence") And 'driver' never used since introduction in 8002db6336dd ("qxl: convert qxl driver to proper use for reservations") Signed-off-by: YueHaibing Link: http://patchwork.freedesktop.org/patch/msgid/1542029556-88107-1-git-send-email-yuehaibing@huawei.com Signed-off-by: Gerd Hoffmann --- drivers/gpu/drm/qxl/qxl_release.c | 4 ---- 1 file changed, 4 deletions(-) (limited to 'drivers/gpu/drm') diff --git a/drivers/gpu/drm/qxl/qxl_release.c b/drivers/gpu/drm/qxl/qxl_release.c index 3813ec198900..0a693fede05e 100644 --- a/drivers/gpu/drm/qxl/qxl_release.c +++ b/drivers/gpu/drm/qxl/qxl_release.c @@ -427,8 +427,6 @@ void qxl_release_fence_buffer_objects(struct qxl_release *release) struct ttm_buffer_object *bo; struct ttm_bo_global *glob; struct ttm_bo_device *bdev; - struct ttm_bo_driver *driver; - struct qxl_bo *qbo; struct ttm_validate_buffer *entry; struct qxl_device *qdev; @@ -449,14 +447,12 @@ void qxl_release_fence_buffer_objects(struct qxl_release *release) release->id | 0xf0000000, release->base.seqno); trace_dma_fence_emit(&release->base); - driver = bdev->driver; glob = bdev->glob; spin_lock(&glob->lru_lock); list_for_each_entry(entry, &release->bos, head) { bo = entry->bo; - qbo = to_qxl_bo(bo); reservation_object_add_shared_fence(bo->resv, &release->base); ttm_bo_add_to_lru(bo); -- cgit v1.2.3 From ed3cafa79ea756be653d22087c017af95ea78a49 Mon Sep 17 00:00:00 2001 From: Stephen Boyd Date: Wed, 26 Sep 2018 11:02:34 -0700 Subject: soc: qcom: cmd-db: Stop memcpy()ing in cmd_db_read_aux_data() Let's change the function signature to return the pointer to memory or an error pointer on failure, and take an argument that lets us return the size of the aux data read. This way we can remove the cmd_db_read_aux_data_len() API entirely and also get rid of the memcpy operation from cmd_db to the caller. Updating the only user of this code shows that making this change allows us to remove a function and put the lookup where the user is. Cc: Mahesh Sivasubramanian Cc: Lina Iyer Cc: Bjorn Andersson Cc: Evan Green Cc: Jordan Crouse Cc: Rob Clark Signed-off-by: Stephen Boyd Signed-off-by: Andy Gross --- drivers/gpu/drm/msm/adreno/a6xx_gmu.c | 54 ++++++++++++----------------------- drivers/soc/qcom/cmd-db.c | 43 ++++++---------------------- include/soc/qcom/cmd-db.h | 12 ++------ 3 files changed, 30 insertions(+), 79 deletions(-) (limited to 'drivers/gpu/drm') diff --git a/drivers/gpu/drm/msm/adreno/a6xx_gmu.c b/drivers/gpu/drm/msm/adreno/a6xx_gmu.c index d4e98e5876bc..546599a7ab05 100644 --- a/drivers/gpu/drm/msm/adreno/a6xx_gmu.c +++ b/drivers/gpu/drm/msm/adreno/a6xx_gmu.c @@ -902,26 +902,6 @@ static int a6xx_gmu_memory_probe(struct a6xx_gmu *gmu) return ret; } -/* Get the list of RPMh voltage levels from cmd-db */ -static int a6xx_gmu_rpmh_arc_cmds(const char *id, void *vals, int size) -{ - u32 len = cmd_db_read_aux_data_len(id); - - if (!len) - return 0; - - if (WARN_ON(len > size)) - return -EINVAL; - - cmd_db_read_aux_data(id, vals, len); - - /* - * The data comes back as an array of unsigned shorts so adjust the - * count accordingly - */ - return len >> 1; -} - /* Return the 'arc-level' for the given frequency */ static u32 a6xx_gmu_get_arc_level(struct device *dev, unsigned long freq) { @@ -949,11 +929,25 @@ static u32 a6xx_gmu_get_arc_level(struct device *dev, unsigned long freq) } static int a6xx_gmu_rpmh_arc_votes_init(struct device *dev, u32 *votes, - unsigned long *freqs, int freqs_count, - u16 *pri, int pri_count, - u16 *sec, int sec_count) + unsigned long *freqs, int freqs_count, const char *id) { int i, j; + const u16 *pri, *sec; + size_t pri_count, sec_count; + + pri = cmd_db_read_aux_data(id, &pri_count); + /* + * The data comes back as an array of unsigned shorts so adjust the + * count accordingly + */ + pri_count >>= 1; + if (!pri_count) + return -EINVAL; + + sec = cmd_db_read_aux_data("mx.lvl", &sec_count); + sec_count >>= 1; + if (!sec_count) + return -EINVAL; /* Construct a vote for each frequency */ for (i = 0; i < freqs_count; i++) { @@ -1012,25 +1006,15 @@ static int a6xx_gmu_rpmh_votes_init(struct a6xx_gmu *gmu) struct a6xx_gpu *a6xx_gpu = container_of(gmu, struct a6xx_gpu, gmu); struct adreno_gpu *adreno_gpu = &a6xx_gpu->base; struct msm_gpu *gpu = &adreno_gpu->base; - - u16 gx[16], cx[16], mx[16]; - u32 gxcount, cxcount, mxcount; int ret; - /* Get the list of available voltage levels for each component */ - gxcount = a6xx_gmu_rpmh_arc_cmds("gfx.lvl", gx, sizeof(gx)); - cxcount = a6xx_gmu_rpmh_arc_cmds("cx.lvl", cx, sizeof(cx)); - mxcount = a6xx_gmu_rpmh_arc_cmds("mx.lvl", mx, sizeof(mx)); - /* Build the GX votes */ ret = a6xx_gmu_rpmh_arc_votes_init(&gpu->pdev->dev, gmu->gx_arc_votes, - gmu->gpu_freqs, gmu->nr_gpu_freqs, - gx, gxcount, mx, mxcount); + gmu->gpu_freqs, gmu->nr_gpu_freqs, "gfx.lvl"); /* Build the CX votes */ ret |= a6xx_gmu_rpmh_arc_votes_init(gmu->dev, gmu->cx_arc_votes, - gmu->gmu_freqs, gmu->nr_gmu_freqs, - cx, cxcount, mx, mxcount); + gmu->gmu_freqs, gmu->nr_gmu_freqs, "cx.lvl"); return ret; } diff --git a/drivers/soc/qcom/cmd-db.c b/drivers/soc/qcom/cmd-db.c index 5c9cc6824891..c701b3b010f1 100644 --- a/drivers/soc/qcom/cmd-db.c +++ b/drivers/soc/qcom/cmd-db.c @@ -192,55 +192,28 @@ EXPORT_SYMBOL(cmd_db_read_addr); /** * cmd_db_read_aux_data() - Query command db for aux data. * - * @id: Resource to retrieve AUX Data on. - * @data: Data buffer to copy returned aux data to. Returns size on NULL - * @len: Caller provides size of data buffer passed in. + * @id: Resource to retrieve AUX Data on + * @len: size of data buffer returned * - * Return: size of data on success, errno otherwise + * Return: pointer to data on success, error pointer otherwise */ -int cmd_db_read_aux_data(const char *id, u8 *data, size_t len) +const void *cmd_db_read_aux_data(const char *id, size_t *len) { int ret; const struct entry_header *ent; const struct rsc_hdr *rsc_hdr; - u16 ent_len; - - if (!data) - return -EINVAL; ret = cmd_db_get_header(id, &ent, &rsc_hdr); if (ret) - return ret; - - ent_len = le16_to_cpu(ent->len); - if (len < ent_len) - return -EINVAL; + return ERR_PTR(ret); - len = min_t(u16, ent_len, len); - memcpy(data, rsc_offset(rsc_hdr, ent), len); + if (len) + *len = le16_to_cpu(ent->len); - return len; + return rsc_offset(rsc_hdr, ent); } EXPORT_SYMBOL(cmd_db_read_aux_data); -/** - * cmd_db_read_aux_data_len - Get the length of the auxiliary data stored in DB. - * - * @id: Resource to retrieve AUX Data. - * - * Return: size on success, 0 on error - */ -size_t cmd_db_read_aux_data_len(const char *id) -{ - int ret; - const struct entry_header *ent; - - ret = cmd_db_get_header(id, &ent, NULL); - - return ret < 0 ? 0 : le16_to_cpu(ent->len); -} -EXPORT_SYMBOL(cmd_db_read_aux_data_len); - /** * cmd_db_read_slave_id - Get the slave ID for a given resource address * diff --git a/include/soc/qcom/cmd-db.h b/include/soc/qcom/cmd-db.h index 578180cbc134..af9722223925 100644 --- a/include/soc/qcom/cmd-db.h +++ b/include/soc/qcom/cmd-db.h @@ -18,9 +18,7 @@ enum cmd_db_hw_type { #if IS_ENABLED(CONFIG_QCOM_COMMAND_DB) u32 cmd_db_read_addr(const char *resource_id); -int cmd_db_read_aux_data(const char *resource_id, u8 *data, size_t len); - -size_t cmd_db_read_aux_data_len(const char *resource_id); +const void *cmd_db_read_aux_data(const char *resource_id, size_t *len); enum cmd_db_hw_type cmd_db_read_slave_id(const char *resource_id); @@ -29,12 +27,8 @@ int cmd_db_ready(void); static inline u32 cmd_db_read_addr(const char *resource_id) { return 0; } -static inline int cmd_db_read_aux_data(const char *resource_id, u8 *data, - size_t len) -{ return -ENODEV; } - -static inline size_t cmd_db_read_aux_data_len(const char *resource_id) -{ return -ENODEV; } +static inline const void *cmd_db_read_aux_data(const char *resource_id, size_t *len) +{ return ERR_PTR(-ENODEV); } static inline enum cmd_db_hw_type cmd_db_read_slave_id(const char *resource_id) { return -ENODEV; } -- cgit v1.2.3 From 8817b44aa9c6cc7207eed260ddd84b9a5e121997 Mon Sep 17 00:00:00 2001 From: Gabriel Krisman Bertazi Date: Thu, 18 Oct 2018 15:31:36 -0400 Subject: drm: panel-orientation-quirks: Do rotation quirk for new GPD Win2 FW I just got a new GDP Win2 device with an updated firmware, which still requires this quirk to get the rotation right, so add the new firmware date to the quirk matching table. This should go to drm-misc-next. Signed-off-by: Gabriel Krisman Bertazi Reviewed-by: Hans de Goede Signed-off-by: Maarten Lankhorst Link: https://patchwork.freedesktop.org/patch/msgid/20181018193136.4910-1-krisman@collabora.co.uk --- drivers/gpu/drm/drm_panel_orientation_quirks.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/gpu/drm') diff --git a/drivers/gpu/drm/drm_panel_orientation_quirks.c b/drivers/gpu/drm/drm_panel_orientation_quirks.c index ab4e70e63f6e..52e445bb1aa5 100644 --- a/drivers/gpu/drm/drm_panel_orientation_quirks.c +++ b/drivers/gpu/drm/drm_panel_orientation_quirks.c @@ -63,7 +63,7 @@ static const struct drm_dmi_panel_orientation_data gpd_win2 = { .width = 720, .height = 1280, .bios_dates = (const char * const []){ - "12/07/2017", "05/24/2018", NULL }, + "12/07/2017", "05/24/2018", "06/29/2018", NULL }, .orientation = DRM_MODE_PANEL_ORIENTATION_RIGHT_UP, }; -- cgit v1.2.3 From 21d808405fe49028036932dd969920f4fee4f481 Mon Sep 17 00:00:00 2001 From: Fabrizio Castro Date: Tue, 6 Nov 2018 11:52:36 +0000 Subject: drm/bridge/sii902x: Fix EDID readback MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit While adding SiI9022A support to the iwg23s board, it came up that when the HDMI transmitter is in pass through mode the device is not compliant with the I2C specification anymore, as it requires a far bigger tbuf, due to a delay the HDMI transmitter is adding when relaying the STOP condition on the monitor i2c side of things. When not providing an appropriate delay after the STOP condition the i2c bus would get stuck. Also, any other traffic on the bus while talking to the monitor may cause the transaction to fail or even cause issues with the i2c bus as well. I2c-gates seemed to reach consent as a possible way to address these issues, and as such this patch is implementing a solution based on that. Since others are clearly relying on the current implementation of the driver, this patch won't require any DT changes. Since we don't want any interference during the DDC Bus Request/Grant procedure and while talking to the monitor, we have to use the adapter locking primitives rather than the i2c-mux locking primitives. Signed-off-by: Fabrizio Castro Reviewed-by: Peter Rosin Acked-by: Linus Walleij Tested-by: Yannick Fertré Signed-off-by: Boris Brezillon Link: https://patchwork.freedesktop.org/patch/msgid/1541505156-8097-1-git-send-email-fabrizio.castro@bp.renesas.com --- drivers/gpu/drm/bridge/sii902x.c | 247 ++++++++++++++++++++++++++++----------- 1 file changed, 178 insertions(+), 69 deletions(-) (limited to 'drivers/gpu/drm') diff --git a/drivers/gpu/drm/bridge/sii902x.c b/drivers/gpu/drm/bridge/sii902x.c index e59a13542333..bfa902013aa4 100644 --- a/drivers/gpu/drm/bridge/sii902x.c +++ b/drivers/gpu/drm/bridge/sii902x.c @@ -1,4 +1,6 @@ /* + * Copyright (C) 2018 Renesas Electronics + * * Copyright (C) 2016 Atmel * Bo Shen * @@ -21,6 +23,7 @@ */ #include +#include #include #include #include @@ -86,8 +89,49 @@ struct sii902x { struct drm_bridge bridge; struct drm_connector connector; struct gpio_desc *reset_gpio; + struct i2c_mux_core *i2cmux; }; +static int sii902x_read_unlocked(struct i2c_client *i2c, u8 reg, u8 *val) +{ + union i2c_smbus_data data; + int ret; + + ret = __i2c_smbus_xfer(i2c->adapter, i2c->addr, i2c->flags, + I2C_SMBUS_READ, reg, I2C_SMBUS_BYTE_DATA, &data); + + if (ret < 0) + return ret; + + *val = data.byte; + return 0; +} + +static int sii902x_write_unlocked(struct i2c_client *i2c, u8 reg, u8 val) +{ + union i2c_smbus_data data; + + data.byte = val; + + return __i2c_smbus_xfer(i2c->adapter, i2c->addr, i2c->flags, + I2C_SMBUS_WRITE, reg, I2C_SMBUS_BYTE_DATA, + &data); +} + +static int sii902x_update_bits_unlocked(struct i2c_client *i2c, u8 reg, u8 mask, + u8 val) +{ + int ret; + u8 status; + + ret = sii902x_read_unlocked(i2c, reg, &status); + if (ret) + return ret; + status &= ~mask; + status |= val & mask; + return sii902x_write_unlocked(i2c, reg, status); +} + static inline struct sii902x *bridge_to_sii902x(struct drm_bridge *bridge) { return container_of(bridge, struct sii902x, bridge); @@ -135,41 +179,11 @@ static const struct drm_connector_funcs sii902x_connector_funcs = { static int sii902x_get_modes(struct drm_connector *connector) { struct sii902x *sii902x = connector_to_sii902x(connector); - struct regmap *regmap = sii902x->regmap; u32 bus_format = MEDIA_BUS_FMT_RGB888_1X24; - struct device *dev = &sii902x->i2c->dev; - unsigned long timeout; - unsigned int retries; - unsigned int status; struct edid *edid; - int num = 0; - int ret; - - ret = regmap_update_bits(regmap, SII902X_SYS_CTRL_DATA, - SII902X_SYS_CTRL_DDC_BUS_REQ, - SII902X_SYS_CTRL_DDC_BUS_REQ); - if (ret) - return ret; - - timeout = jiffies + - msecs_to_jiffies(SII902X_I2C_BUS_ACQUISITION_TIMEOUT_MS); - do { - ret = regmap_read(regmap, SII902X_SYS_CTRL_DATA, &status); - if (ret) - return ret; - } while (!(status & SII902X_SYS_CTRL_DDC_BUS_GRTD) && - time_before(jiffies, timeout)); + int num = 0, ret; - if (!(status & SII902X_SYS_CTRL_DDC_BUS_GRTD)) { - dev_err(dev, "failed to acquire the i2c bus\n"); - return -ETIMEDOUT; - } - - ret = regmap_write(regmap, SII902X_SYS_CTRL_DATA, status); - if (ret) - return ret; - - edid = drm_get_edid(connector, sii902x->i2c->adapter); + edid = drm_get_edid(connector, sii902x->i2cmux->adapter[0]); drm_connector_update_edid_property(connector, edid); if (edid) { num = drm_add_edid_modes(connector, edid); @@ -181,42 +195,6 @@ static int sii902x_get_modes(struct drm_connector *connector) if (ret) return ret; - /* - * Sometimes the I2C bus can stall after failure to use the - * EDID channel. Retry a few times to see if things clear - * up, else continue anyway. - */ - retries = 5; - do { - ret = regmap_read(regmap, SII902X_SYS_CTRL_DATA, - &status); - retries--; - } while (ret && retries); - if (ret) - dev_err(dev, "failed to read status (%d)\n", ret); - - ret = regmap_update_bits(regmap, SII902X_SYS_CTRL_DATA, - SII902X_SYS_CTRL_DDC_BUS_REQ | - SII902X_SYS_CTRL_DDC_BUS_GRTD, 0); - if (ret) - return ret; - - timeout = jiffies + - msecs_to_jiffies(SII902X_I2C_BUS_ACQUISITION_TIMEOUT_MS); - do { - ret = regmap_read(regmap, SII902X_SYS_CTRL_DATA, &status); - if (ret) - return ret; - } while (status & (SII902X_SYS_CTRL_DDC_BUS_REQ | - SII902X_SYS_CTRL_DDC_BUS_GRTD) && - time_before(jiffies, timeout)); - - if (status & (SII902X_SYS_CTRL_DDC_BUS_REQ | - SII902X_SYS_CTRL_DDC_BUS_GRTD)) { - dev_err(dev, "failed to release the i2c bus\n"); - return -ETIMEDOUT; - } - return num; } @@ -366,6 +344,121 @@ static irqreturn_t sii902x_interrupt(int irq, void *data) return IRQ_HANDLED; } +/* + * The purpose of sii902x_i2c_bypass_select is to enable the pass through + * mode of the HDMI transmitter. Do not use regmap from within this function, + * only use sii902x_*_unlocked functions to read/modify/write registers. + * We are holding the parent adapter lock here, keep this in mind before + * adding more i2c transactions. + * + * Also, since SII902X_SYS_CTRL_DATA is used with regmap_update_bits elsewhere + * in this driver, we need to make sure that we only touch 0x1A[2:1] from + * within sii902x_i2c_bypass_select and sii902x_i2c_bypass_deselect, and that + * we leave the remaining bits as we have found them. + */ +static int sii902x_i2c_bypass_select(struct i2c_mux_core *mux, u32 chan_id) +{ + struct sii902x *sii902x = i2c_mux_priv(mux); + struct device *dev = &sii902x->i2c->dev; + unsigned long timeout; + u8 status; + int ret; + + ret = sii902x_update_bits_unlocked(sii902x->i2c, SII902X_SYS_CTRL_DATA, + SII902X_SYS_CTRL_DDC_BUS_REQ, + SII902X_SYS_CTRL_DDC_BUS_REQ); + if (ret) + return ret; + + timeout = jiffies + + msecs_to_jiffies(SII902X_I2C_BUS_ACQUISITION_TIMEOUT_MS); + do { + ret = sii902x_read_unlocked(sii902x->i2c, SII902X_SYS_CTRL_DATA, + &status); + if (ret) + return ret; + } while (!(status & SII902X_SYS_CTRL_DDC_BUS_GRTD) && + time_before(jiffies, timeout)); + + if (!(status & SII902X_SYS_CTRL_DDC_BUS_GRTD)) { + dev_err(dev, "Failed to acquire the i2c bus\n"); + return -ETIMEDOUT; + } + + return sii902x_write_unlocked(sii902x->i2c, SII902X_SYS_CTRL_DATA, + status); +} + +/* + * The purpose of sii902x_i2c_bypass_deselect is to disable the pass through + * mode of the HDMI transmitter. Do not use regmap from within this function, + * only use sii902x_*_unlocked functions to read/modify/write registers. + * We are holding the parent adapter lock here, keep this in mind before + * adding more i2c transactions. + * + * Also, since SII902X_SYS_CTRL_DATA is used with regmap_update_bits elsewhere + * in this driver, we need to make sure that we only touch 0x1A[2:1] from + * within sii902x_i2c_bypass_select and sii902x_i2c_bypass_deselect, and that + * we leave the remaining bits as we have found them. + */ +static int sii902x_i2c_bypass_deselect(struct i2c_mux_core *mux, u32 chan_id) +{ + struct sii902x *sii902x = i2c_mux_priv(mux); + struct device *dev = &sii902x->i2c->dev; + unsigned long timeout; + unsigned int retries; + u8 status; + int ret; + + /* + * When the HDMI transmitter is in pass through mode, we need an + * (undocumented) additional delay between STOP and START conditions + * to guarantee the bus won't get stuck. + */ + udelay(30); + + /* + * Sometimes the I2C bus can stall after failure to use the + * EDID channel. Retry a few times to see if things clear + * up, else continue anyway. + */ + retries = 5; + do { + ret = sii902x_read_unlocked(sii902x->i2c, SII902X_SYS_CTRL_DATA, + &status); + retries--; + } while (ret && retries); + if (ret) { + dev_err(dev, "failed to read status (%d)\n", ret); + return ret; + } + + ret = sii902x_update_bits_unlocked(sii902x->i2c, SII902X_SYS_CTRL_DATA, + SII902X_SYS_CTRL_DDC_BUS_REQ | + SII902X_SYS_CTRL_DDC_BUS_GRTD, 0); + if (ret) + return ret; + + timeout = jiffies + + msecs_to_jiffies(SII902X_I2C_BUS_ACQUISITION_TIMEOUT_MS); + do { + ret = sii902x_read_unlocked(sii902x->i2c, SII902X_SYS_CTRL_DATA, + &status); + if (ret) + return ret; + } while (status & (SII902X_SYS_CTRL_DDC_BUS_REQ | + SII902X_SYS_CTRL_DDC_BUS_GRTD) && + time_before(jiffies, timeout)); + + if (status & (SII902X_SYS_CTRL_DDC_BUS_REQ | + SII902X_SYS_CTRL_DDC_BUS_GRTD)) { + dev_err(dev, "failed to release the i2c bus\n"); + return -ETIMEDOUT; + } + + return 0; +} + static int sii902x_probe(struct i2c_client *client, const struct i2c_device_id *id) { @@ -375,6 +468,13 @@ static int sii902x_probe(struct i2c_client *client, u8 chipid[4]; int ret; + ret = i2c_check_functionality(client->adapter, + I2C_FUNC_SMBUS_BYTE_DATA); + if (!ret) { + dev_err(dev, "I2C adapter not suitable\n"); + return -EIO; + } + sii902x = devm_kzalloc(dev, sizeof(*sii902x), GFP_KERNEL); if (!sii902x) return -ENOMEM; @@ -433,7 +533,15 @@ static int sii902x_probe(struct i2c_client *client, i2c_set_clientdata(client, sii902x); - return 0; + sii902x->i2cmux = i2c_mux_alloc(client->adapter, dev, + 1, 0, I2C_MUX_GATE, + sii902x_i2c_bypass_select, + sii902x_i2c_bypass_deselect); + if (!sii902x->i2cmux) + return -ENOMEM; + + sii902x->i2cmux->priv = sii902x; + return i2c_mux_add_adapter(sii902x->i2cmux, 0, 0, 0); } static int sii902x_remove(struct i2c_client *client) @@ -441,6 +549,7 @@ static int sii902x_remove(struct i2c_client *client) { struct sii902x *sii902x = i2c_get_clientdata(client); + i2c_mux_del_adapters(sii902x->i2cmux); drm_bridge_remove(&sii902x->bridge); return 0; -- cgit v1.2.3 From 5a43911fd256f1c9748f3f82aee1c3a3adad2719 Mon Sep 17 00:00:00 2001 From: Boris Brezillon Date: Thu, 15 Nov 2018 11:58:51 +0100 Subject: drm/vc4: Fix NULL pointer dereference in the async update path vc4_plane_atomic_async_update() calls vc4_plane_atomic_check() which in turn calls vc4_plane_setup_clipping_and_scaling(), and since commit 58a6a36fe8e0 ("drm/vc4: Use drm_atomic_helper_check_plane_state() to simplify the logic"), this function accesses plane_state->state which will be NULL when called from the async update path because we're passing the current plane state, and plane_state->state has been assigned to NULL in drm_atomic_helper_swap_state(). Pass the new state instead of the current one (the new state has ->state set to a non-NULL value). Fixes: 58a6a36fe8e0 ("drm/vc4: Use drm_atomic_helper_check_plane_state() to simplify the logic") Signed-off-by: Boris Brezillon Reviewed-by: Eric Anholt Link: https://patchwork.freedesktop.org/patch/msgid/20181115105852.9844-1-boris.brezillon@bootlin.com --- drivers/gpu/drm/vc4/vc4_plane.c | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) (limited to 'drivers/gpu/drm') diff --git a/drivers/gpu/drm/vc4/vc4_plane.c b/drivers/gpu/drm/vc4/vc4_plane.c index 9dc3fcbd290b..c6635f23918a 100644 --- a/drivers/gpu/drm/vc4/vc4_plane.c +++ b/drivers/gpu/drm/vc4/vc4_plane.c @@ -807,7 +807,7 @@ void vc4_plane_async_set_fb(struct drm_plane *plane, struct drm_framebuffer *fb) static void vc4_plane_atomic_async_update(struct drm_plane *plane, struct drm_plane_state *state) { - struct vc4_plane_state *vc4_state = to_vc4_plane_state(plane->state); + struct vc4_plane_state *vc4_state, *new_vc4_state; if (plane->state->fb != state->fb) { vc4_plane_async_set_fb(plane, state->fb); @@ -828,7 +828,18 @@ static void vc4_plane_atomic_async_update(struct drm_plane *plane, plane->state->src_y = state->src_y; /* Update the display list based on the new crtc_x/y. */ - vc4_plane_atomic_check(plane, plane->state); + vc4_plane_atomic_check(plane, state); + + new_vc4_state = to_vc4_plane_state(state); + vc4_state = to_vc4_plane_state(plane->state); + + /* Update the current vc4_state pos0, pos2 and ptr0 dlist entries. */ + vc4_state->dlist[vc4_state->pos0_offset] = + new_vc4_state->dlist[vc4_state->pos0_offset]; + vc4_state->dlist[vc4_state->pos2_offset] = + new_vc4_state->dlist[vc4_state->pos2_offset]; + vc4_state->dlist[vc4_state->ptr0_offset] = + new_vc4_state->dlist[vc4_state->ptr0_offset]; /* Note that we can't just call vc4_plane_write_dlist() * because that would smash the context data that the HVS is -- cgit v1.2.3 From fcc86cb45d38ca2f24bcea9c29c7f4742041caed Mon Sep 17 00:00:00 2001 From: Boris Brezillon Date: Thu, 15 Nov 2018 11:58:52 +0100 Subject: drm/vc4: Set ->legacy_cursor_update to false when doing non-async updates drm_atomic_helper_setup_commit() auto-completes commit->flip_done when state->legacy_cursor_update is true, but we know for sure that we want a sync update when we call drm_atomic_helper_setup_commit() from vc4_atomic_commit(). Explicitly set state->legacy_cursor_update to false to prevent this auto-completion. Fixes: 184d3cf4f738 ("drm/vc4: Use wait_for_flip_done() instead of wait_for_vblanks()") Cc: Signed-off-by: Boris Brezillon Reviewed-by: Eric Anholt Link: https://patchwork.freedesktop.org/patch/msgid/20181115105852.9844-2-boris.brezillon@bootlin.com --- drivers/gpu/drm/vc4/vc4_kms.c | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'drivers/gpu/drm') diff --git a/drivers/gpu/drm/vc4/vc4_kms.c b/drivers/gpu/drm/vc4/vc4_kms.c index 127468785f74..1f94b9affe4b 100644 --- a/drivers/gpu/drm/vc4/vc4_kms.c +++ b/drivers/gpu/drm/vc4/vc4_kms.c @@ -214,6 +214,12 @@ static int vc4_atomic_commit(struct drm_device *dev, return 0; } + /* We know for sure we don't want an async update here. Set + * state->legacy_cursor_update to false to prevent + * drm_atomic_helper_setup_commit() from auto-completing + * commit->flip_done. + */ + state->legacy_cursor_update = false; ret = drm_atomic_helper_setup_commit(state, nonblock); if (ret) return ret; -- cgit v1.2.3 From 69756c6ff0de478c10100481f16c966dde3b5339 Mon Sep 17 00:00:00 2001 From: Nicholas Kazlauskas Date: Thu, 15 Nov 2018 17:19:12 -0500 Subject: drm/amdgpu: Add amdgpu "max bpc" connector property (v2) [Why] Many panels support more than 8bpc but some modes are unavailable while running at greater than 8bpc due to DP/HDMI bandwidth constraints. Support for more than 8bpc was added recently in the driver but it defaults to the maximum supported bpc - locking out these modes. This should be a user configurable option such that the user can select what bpc configuration they would like. [How] This patch introduces the "max bpc" amdgpu driver specific connector property so the user can limit the maximum bpc. It ranges from 8 to 16. This doesn't directly set the preferred bpc for the panel since it follows Intel's existing driver conventions. This proprety should be removed once common drm support for max bpc lands. v2: rebase on upstream (Alex) Signed-off-by: Nicholas Kazlauskas Acked-by: Alex Deucher Reviewed-by: Harry Wentland Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/amdgpu_display.c | 7 +++++++ drivers/gpu/drm/amd/amdgpu/amdgpu_mode.h | 2 ++ 2 files changed, 9 insertions(+) (limited to 'drivers/gpu/drm') diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_display.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_display.c index 6748cd7fc129..686a26de50f9 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_display.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_display.c @@ -626,6 +626,13 @@ int amdgpu_display_modeset_create_props(struct amdgpu_device *adev) "dither", amdgpu_dither_enum_list, sz); + if (amdgpu_device_has_dc_support(adev)) { + adev->mode_info.max_bpc_property = + drm_property_create_range(adev->ddev, 0, "max bpc", 8, 16); + if (!adev->mode_info.max_bpc_property) + return -ENOMEM; + } + return 0; } diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_mode.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_mode.h index b9e9e8b02fb7..d1b4d9b6aae0 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_mode.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_mode.h @@ -339,6 +339,8 @@ struct amdgpu_mode_info { struct drm_property *audio_property; /* FMT dithering */ struct drm_property *dither_property; + /* maximum number of bits per channel for monitor color */ + struct drm_property *max_bpc_property; /* hardcoded DFP edid from BIOS */ struct edid *bios_hardcoded_edid; int bios_hardcoded_edid_size; -- cgit v1.2.3 From 07e3a1cfb0568b6d8d7862077029af96af6690ea Mon Sep 17 00:00:00 2001 From: Nicholas Kazlauskas Date: Thu, 15 Nov 2018 17:21:34 -0500 Subject: drm/amd/display: Support amdgpu "max bpc" connector property (v2) [Why] Many panels support more than 8bpc but some modes are unavailable while running at greater than 8bpc due to DP/HDMI bandwidth constraints. Support for more than 8bpc was added recently in the driver but it defaults to the maximum supported bpc - locking out these modes. This should be a user configurable option such that the user can select what bpc configuration they would like. [How] This patch adds support for getting and setting the amdgpu driver specific "max bpc" property on the connector. It also adds support for limiting the output bpc based on the property value. The default limitation is the lowest value in the range, 8bpc. This was the old value before the range was uncapped. This patch should be updated/replaced later once common drm support for max bpc lands. Bugzilla: https://bugs.freedesktop.org/108542 Bugzilla: https://bugzilla.kernel.org/show_bug.cgi?id=201585 Bugzilla: https://bugzilla.kernel.org/show_bug.cgi?id=200645 Fixes: e03fd3f300f6 ("drm/amd/display: Do not limit color depth to 8bpc") v2: rebase on upstream (Alex) Signed-off-by: Nicholas Kazlauskas Acked-by: Alex Deucher Reviewed-by: Harry Wentland Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 16 ++++++++++++++++ drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h | 1 + 2 files changed, 17 insertions(+) (limited to 'drivers/gpu/drm') diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c index c1262f62cd9f..ca925200fe09 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c @@ -2358,8 +2358,15 @@ static void update_stream_scaling_settings(const struct drm_display_mode *mode, static enum dc_color_depth convert_color_depth_from_display_info(const struct drm_connector *connector) { + struct dm_connector_state *dm_conn_state = + to_dm_connector_state(connector->state); uint32_t bpc = connector->display_info.bpc; + /* TODO: Remove this when there's support for max_bpc in drm */ + if (dm_conn_state && bpc > dm_conn_state->max_bpc) + /* Round down to nearest even number. */ + bpc = dm_conn_state->max_bpc - (dm_conn_state->max_bpc & 1); + switch (bpc) { case 0: /* @@ -2943,6 +2950,9 @@ int amdgpu_dm_connector_atomic_set_property(struct drm_connector *connector, } else if (property == adev->mode_info.underscan_property) { dm_new_state->underscan_enable = val; ret = 0; + } else if (property == adev->mode_info.max_bpc_property) { + dm_new_state->max_bpc = val; + ret = 0; } return ret; @@ -2985,6 +2995,9 @@ int amdgpu_dm_connector_atomic_get_property(struct drm_connector *connector, } else if (property == adev->mode_info.underscan_property) { *val = dm_state->underscan_enable; ret = 0; + } else if (property == adev->mode_info.max_bpc_property) { + *val = dm_state->max_bpc; + ret = 0; } return ret; } @@ -3795,6 +3808,9 @@ void amdgpu_dm_connector_init_helper(struct amdgpu_display_manager *dm, drm_object_attach_property(&aconnector->base.base, adev->mode_info.underscan_vborder_property, 0); + drm_object_attach_property(&aconnector->base.base, + adev->mode_info.max_bpc_property, + 0); } diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h index 924a38a1fc44..6e069d777ab2 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h @@ -204,6 +204,7 @@ struct dm_connector_state { enum amdgpu_rmx_type scaling; uint8_t underscan_vborder; uint8_t underscan_hborder; + uint8_t max_bpc; bool underscan_enable; bool freesync_enable; bool freesync_capable; -- cgit v1.2.3 From 5478ad10e7850ce3d8b7056db05ddfa3c9ddad9a Mon Sep 17 00:00:00 2001 From: Thomas Zimmermann Date: Thu, 15 Nov 2018 11:42:16 +0100 Subject: drm/ast: Remove existing framebuffers before loading driver If vesafb attaches to the AST device, it configures the framebuffer memory for uncached access by default. When ast.ko later tries to attach itself to the device, it wants to use write-combining on the framebuffer memory, but vesefb's existing configuration for uncached access takes precedence. This results in reduced performance. Removing the framebuffer's configuration before loding the AST driver fixes the problem. Other DRM drivers already contain equivalent code. Link: https://bugzilla.opensuse.org/show_bug.cgi?id=1112963 Signed-off-by: Thomas Zimmermann Cc: Tested-by: Y.C. Chen Reviewed-by: Jean Delvare Tested-by: Jean Delvare Signed-off-by: Dave Airlie --- drivers/gpu/drm/ast/ast_drv.c | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) (limited to 'drivers/gpu/drm') diff --git a/drivers/gpu/drm/ast/ast_drv.c b/drivers/gpu/drm/ast/ast_drv.c index 69dab82a3771..bf589c53b908 100644 --- a/drivers/gpu/drm/ast/ast_drv.c +++ b/drivers/gpu/drm/ast/ast_drv.c @@ -60,8 +60,29 @@ static const struct pci_device_id pciidlist[] = { MODULE_DEVICE_TABLE(pci, pciidlist); +static void ast_kick_out_firmware_fb(struct pci_dev *pdev) +{ + struct apertures_struct *ap; + bool primary = false; + + ap = alloc_apertures(1); + if (!ap) + return; + + ap->ranges[0].base = pci_resource_start(pdev, 0); + ap->ranges[0].size = pci_resource_len(pdev, 0); + +#ifdef CONFIG_X86 + primary = pdev->resource[PCI_ROM_RESOURCE].flags & IORESOURCE_ROM_SHADOW; +#endif + drm_fb_helper_remove_conflicting_framebuffers(ap, "astdrmfb", primary); + kfree(ap); +} + static int ast_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) { + ast_kick_out_firmware_fb(pdev); + return drm_get_pci_dev(pdev, ent, &driver); } -- cgit v1.2.3 From 21556350ade3cb5d7afecc8b3544e56431d21695 Mon Sep 17 00:00:00 2001 From: Ville Syrjälä Date: Wed, 14 Nov 2018 19:34:40 +0200 Subject: drm/i915: Disable LP3 watermarks on all SNB machines MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit I have a Thinkpad X220 Tablet in my hands that is losing vblank interrupts whenever LP3 watermarks are used. If I nudge the latency value written to the WM3 register just by one in either direction the problem disappears. That to me suggests that the punit will not enter the corrsponding powersave mode (MPLL shutdown IIRC) unless the latency value in the register matches exactly what we read from SSKPD. Ie. it's not really a latency value but rather just a cookie by which the punit can identify the desired power saving state. On HSW/BDW this was changed such that we actually just write the WM level number into those bits, which makes much more sense given the observed behaviour. We could try to handle this by disallowing LP3 watermarks only when vblank interrupts are enabled but we'd first have to prove that only vblank interrupts are affected, which seems unlikely. Also we can't grab the wm mutex from the vblank enable/disable hooks because those are called with various spinlocks held. Thus we'd have to redesigne the watermark locking. So to play it safe and keep the code simple we simply disable LP3 watermarks on all SNB machines. To do that we simply zero out the latency values for watermark level 3, and we adjust the watermark computation to check for that. The behaviour now matches that of the g4x/vlv/skl wm code in the presence of a zeroed latency value. v2: s/USHRT_MAX/U32_MAX/ for consistency with the types (Chris) Cc: stable@vger.kernel.org Cc: Chris Wilson Acked-by: Chris Wilson Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=101269 Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=103713 Signed-off-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20181114173440.6730-1-ville.syrjala@linux.intel.com (cherry picked from commit 03981c6ebec4fc7056b9b45f847393aeac90d060) Signed-off-by: Joonas Lahtinen --- drivers/gpu/drm/i915/intel_pm.c | 41 ++++++++++++++++++++++++++++++++++++++++- 1 file changed, 40 insertions(+), 1 deletion(-) (limited to 'drivers/gpu/drm') diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index 245f0022bcfd..3fe358db1276 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -2493,6 +2493,9 @@ static uint32_t ilk_compute_pri_wm(const struct intel_crtc_state *cstate, uint32_t method1, method2; int cpp; + if (mem_value == 0) + return U32_MAX; + if (!intel_wm_plane_visible(cstate, pstate)) return 0; @@ -2522,6 +2525,9 @@ static uint32_t ilk_compute_spr_wm(const struct intel_crtc_state *cstate, uint32_t method1, method2; int cpp; + if (mem_value == 0) + return U32_MAX; + if (!intel_wm_plane_visible(cstate, pstate)) return 0; @@ -2545,6 +2551,9 @@ static uint32_t ilk_compute_cur_wm(const struct intel_crtc_state *cstate, { int cpp; + if (mem_value == 0) + return U32_MAX; + if (!intel_wm_plane_visible(cstate, pstate)) return 0; @@ -3008,6 +3017,34 @@ static void snb_wm_latency_quirk(struct drm_i915_private *dev_priv) intel_print_wm_latency(dev_priv, "Cursor", dev_priv->wm.cur_latency); } +static void snb_wm_lp3_irq_quirk(struct drm_i915_private *dev_priv) +{ + /* + * On some SNB machines (Thinkpad X220 Tablet at least) + * LP3 usage can cause vblank interrupts to be lost. + * The DEIIR bit will go high but it looks like the CPU + * never gets interrupted. + * + * It's not clear whether other interrupt source could + * be affected or if this is somehow limited to vblank + * interrupts only. To play it safe we disable LP3 + * watermarks entirely. + */ + if (dev_priv->wm.pri_latency[3] == 0 && + dev_priv->wm.spr_latency[3] == 0 && + dev_priv->wm.cur_latency[3] == 0) + return; + + dev_priv->wm.pri_latency[3] = 0; + dev_priv->wm.spr_latency[3] = 0; + dev_priv->wm.cur_latency[3] = 0; + + DRM_DEBUG_KMS("LP3 watermarks disabled due to potential for lost interrupts\n"); + intel_print_wm_latency(dev_priv, "Primary", dev_priv->wm.pri_latency); + intel_print_wm_latency(dev_priv, "Sprite", dev_priv->wm.spr_latency); + intel_print_wm_latency(dev_priv, "Cursor", dev_priv->wm.cur_latency); +} + static void ilk_setup_wm_latency(struct drm_i915_private *dev_priv) { intel_read_wm_latency(dev_priv, dev_priv->wm.pri_latency); @@ -3024,8 +3061,10 @@ static void ilk_setup_wm_latency(struct drm_i915_private *dev_priv) intel_print_wm_latency(dev_priv, "Sprite", dev_priv->wm.spr_latency); intel_print_wm_latency(dev_priv, "Cursor", dev_priv->wm.cur_latency); - if (IS_GEN6(dev_priv)) + if (IS_GEN6(dev_priv)) { snb_wm_latency_quirk(dev_priv); + snb_wm_lp3_irq_quirk(dev_priv); + } } static void skl_setup_wm_latency(struct drm_i915_private *dev_priv) -- cgit v1.2.3 From fa68d4f8476bea4cdf441062b614b41bb85ef1da Mon Sep 17 00:00:00 2001 From: Damian Kos Date: Tue, 6 Nov 2018 15:37:05 +0000 Subject: drm/rockchip: fix for mailbox read size Some of the functions (like cdn_dp_dpcd_read, cdn_dp_get_edid_block) allow to read 64KiB, but the cdn_dp_mailbox_read_receive, that is used by them, can read only up to 255 bytes at once. Normally, it's not a big issue as DPCD or EDID reads won't (hopefully) exceed that value. The real issue here is the revocation list read during the HDCP authentication process. (problematic use case: https://chromium.googlesource.com/chromiumos/third_party/kernel/+/chromeos-4.4/drivers/gpu/drm/rockchip/cdn-dp-reg.c#1152) The list can reach 127*5+4 bytes (num devs * 5 bytes per ID/Bksv + 4 bytes of an additional info). In other words - CTSes with HDCP Repeater won't pass without this fix. Oh, and the driver will most likely stop working (best case scenario). Signed-off-by: Damian Kos Signed-off-by: Heiko Stuebner Link: https://patchwork.freedesktop.org/patch/msgid/1541518625-25984-1-git-send-email-dkos@cadence.com --- drivers/gpu/drm/rockchip/cdn-dp-reg.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/gpu/drm') diff --git a/drivers/gpu/drm/rockchip/cdn-dp-reg.c b/drivers/gpu/drm/rockchip/cdn-dp-reg.c index 3105965fc260..5a485489a1e2 100644 --- a/drivers/gpu/drm/rockchip/cdn-dp-reg.c +++ b/drivers/gpu/drm/rockchip/cdn-dp-reg.c @@ -147,7 +147,7 @@ static int cdn_dp_mailbox_validate_receive(struct cdn_dp_device *dp, } static int cdn_dp_mailbox_read_receive(struct cdn_dp_device *dp, - u8 *buff, u8 buff_size) + u8 *buff, u16 buff_size) { u32 i; int ret; -- cgit v1.2.3 From 2aa0061b9810e79f8e0e7db98fe692729ec8e95f Mon Sep 17 00:00:00 2001 From: Steven Chiu Date: Mon, 15 Oct 2018 14:16:20 -0400 Subject: drm/amd/display: 3.2.05 Signed-off-by: Steven Chiu Reviewed-by: Tony Cheng Acked-by: Bhawanpreet Lakha Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/display/dc/dc.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/gpu/drm') diff --git a/drivers/gpu/drm/amd/display/dc/dc.h b/drivers/gpu/drm/amd/display/dc/dc.h index d16a20c84792..f4bfead398a4 100644 --- a/drivers/gpu/drm/amd/display/dc/dc.h +++ b/drivers/gpu/drm/amd/display/dc/dc.h @@ -38,7 +38,7 @@ #include "inc/compressor.h" #include "dml/display_mode_lib.h" -#define DC_VER "3.2.04" +#define DC_VER "3.2.05" #define MAX_SURFACES 3 #define MAX_STREAMS 6 -- cgit v1.2.3 From 37cd85ce3322706d9d357ffbe54481fa884af9e5 Mon Sep 17 00:00:00 2001 From: David Francis Date: Tue, 16 Oct 2018 14:21:32 -0400 Subject: drm/amd/display: Remove dc_stream_state->status [Why] dc_state has an array of dc_stream_status that contain pointers to the dc_plane_state and other useful information Confusingly, dc_stream_state also contains a dc_stream_status called status. This struct was partially initialized and used in a few places [How] stream->status.link has been replaced with stream->sink->link. If a stream does not have a sink, or a sink does not have a link, something has gone seriously wrong All other properties of stream->status were zeroed by kzalloc and never initialized, so they have been replaced by the number 0 This is a refactor: no functional change is intended Signed-off-by: David Francis Reviewed-by: Harry Wentland Acked-by: Bhawanpreet Lakha Acked-by: Tony Cheng Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/display/dc/core/dc.c | 2 +- drivers/gpu/drm/amd/display/dc/core/dc_stream.c | 2 -- drivers/gpu/drm/amd/display/dc/dc_stream.h | 2 -- drivers/gpu/drm/amd/display/dc/dce110/dce110_hw_sequencer.c | 2 +- drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer.c | 2 +- 5 files changed, 3 insertions(+), 7 deletions(-) (limited to 'drivers/gpu/drm') diff --git a/drivers/gpu/drm/amd/display/dc/core/dc.c b/drivers/gpu/drm/amd/display/dc/core/dc.c index 3279e26c3440..1d8bd554869b 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc.c +++ b/drivers/gpu/drm/amd/display/dc/core/dc.c @@ -328,7 +328,7 @@ void dc_stream_set_dither_option(struct dc_stream_state *stream, enum dc_dither_option option) { struct bit_depth_reduction_params params; - struct dc_link *link = stream->status.link; + struct dc_link *link = stream->sink->link; struct pipe_ctx *pipes = NULL; int i; diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_stream.c b/drivers/gpu/drm/amd/display/dc/core/dc_stream.c index e113439aaa86..780838a05f44 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc_stream.c +++ b/drivers/gpu/drm/amd/display/dc/core/dc_stream.c @@ -100,8 +100,6 @@ static void construct(struct dc_stream_state *stream, /* EDID CAP translation for HDMI 2.0 */ stream->timing.flags.LTE_340MCSC_SCRAMBLE = dc_sink_data->edid_caps.lte_340mcsc_scramble; - stream->status.link = stream->sink->link; - update_stream_signal(stream); stream->out_transfer_func = dc_create_transfer_func(); diff --git a/drivers/gpu/drm/amd/display/dc/dc_stream.h b/drivers/gpu/drm/amd/display/dc/dc_stream.h index c5bd1fbb6982..771d9f17e26e 100644 --- a/drivers/gpu/drm/amd/display/dc/dc_stream.h +++ b/drivers/gpu/drm/amd/display/dc/dc_stream.h @@ -104,8 +104,6 @@ struct dc_stream_state { bool dpms_off; bool apply_edp_fast_boot_optimization; - struct dc_stream_status status; - struct dc_cursor_attributes cursor_attributes; struct dc_cursor_position cursor_position; uint32_t sdr_white_level; // for boosting (SDR) cursor in HDR mode diff --git a/drivers/gpu/drm/amd/display/dc/dce110/dce110_hw_sequencer.c b/drivers/gpu/drm/amd/display/dc/dce110/dce110_hw_sequencer.c index 9724a17e352b..2f062bacd78a 100644 --- a/drivers/gpu/drm/amd/display/dc/dce110/dce110_hw_sequencer.c +++ b/drivers/gpu/drm/amd/display/dc/dce110/dce110_hw_sequencer.c @@ -2282,7 +2282,7 @@ static void dce110_enable_per_frame_crtc_position_reset( int i; gsl_params.gsl_group = 0; - gsl_params.gsl_master = grouped_pipes[0]->stream->triggered_crtc_reset.event_source->status.primary_otg_inst; + gsl_params.gsl_master = 0; for (i = 0; i < group_size; i++) grouped_pipes[i]->stream_res.tg->funcs->setup_global_swap_lock( diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer.c b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer.c index 87495dea45ec..6b8a4da4f3c8 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer.c +++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer.c @@ -1400,7 +1400,7 @@ static void dcn10_enable_per_frame_crtc_position_reset( if (grouped_pipes[i]->stream_res.tg->funcs->enable_crtc_reset) grouped_pipes[i]->stream_res.tg->funcs->enable_crtc_reset( grouped_pipes[i]->stream_res.tg, - grouped_pipes[i]->stream->triggered_crtc_reset.event_source->status.primary_otg_inst, + 0, &grouped_pipes[i]->stream->triggered_crtc_reset); DC_SYNC_INFO("Waiting for trigger\n"); -- cgit v1.2.3 From eb9714a201f46ac46c1314849242d9eba56752e4 Mon Sep 17 00:00:00 2001 From: Wenjing Liu Date: Mon, 22 Oct 2018 16:34:32 -0400 Subject: drm/amd/display: resolve minor log problems [Why] dc_add_stream_to_context is used to check bw requirement. It is not an error if it fails. [How] Replace DC_ERROR with DC_LOG_WARNING. Signed-off-by: Wenjing Liu Reviewed-by: Jun Lei Acked-by: Bhawanpreet Lakha Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/display/dc/core/dc_resource.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers/gpu/drm') diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_resource.c b/drivers/gpu/drm/amd/display/dc/core/dc_resource.c index fc65b0055167..d09aa35f4181 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc_resource.c +++ b/drivers/gpu/drm/amd/display/dc/core/dc_resource.c @@ -1796,11 +1796,11 @@ enum dc_status dc_add_stream_to_ctx( struct dc_state *new_ctx, struct dc_stream_state *stream) { - struct dc_context *dc_ctx = dc->ctx; enum dc_status res; + DC_LOGGER_INIT(dc->ctx->logger); if (new_ctx->stream_count >= dc->res_pool->timing_generator_count) { - DC_ERROR("Max streams reached, can't add stream %p !\n", stream); + DC_LOG_WARNING("Max streams reached, can't add stream %p !\n", stream); return DC_ERROR_UNEXPECTED; } @@ -1810,7 +1810,7 @@ enum dc_status dc_add_stream_to_ctx( res = dc->res_pool->funcs->add_stream_to_ctx(dc, new_ctx, stream); if (res != DC_OK) - DC_ERROR("Adding stream %p to context failed with err %d!\n", stream, res); + DC_LOG_WARNING("Adding stream %p to context failed with err %d!\n", stream, res); return res; } -- cgit v1.2.3 From 261f392429a968604847917e7467ac5e24c8c2c6 Mon Sep 17 00:00:00 2001 From: Nevenko Stupar Date: Tue, 23 Oct 2018 11:36:49 -0400 Subject: drm/amd/display: expose dentist_get_divider_from_did expose this functions for future use. Signed-off-by: Nevenko Stupar Reviewed-by: Tony Cheng Acked-by: Bhawanpreet Lakha Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/display/dc/dce/dce_clk_mgr.c | 2 +- drivers/gpu/drm/amd/display/dc/dce/dce_clk_mgr.h | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) (limited to 'drivers/gpu/drm') diff --git a/drivers/gpu/drm/amd/display/dc/dce/dce_clk_mgr.c b/drivers/gpu/drm/amd/display/dc/dce/dce_clk_mgr.c index 9a28a04417d1..888d7129022e 100644 --- a/drivers/gpu/drm/amd/display/dc/dce/dce_clk_mgr.c +++ b/drivers/gpu/drm/amd/display/dc/dce/dce_clk_mgr.c @@ -94,7 +94,7 @@ static const struct state_dependent_clocks dce120_max_clks_by_state[] = { /*ClocksStatePerformance*/ { .display_clk_khz = 1133000, .pixel_clk_khz = 600000 } }; -static int dentist_get_divider_from_did(int did) +int dentist_get_divider_from_did(int did) { if (did < DENTIST_BASE_DID_1) did = DENTIST_BASE_DID_1; diff --git a/drivers/gpu/drm/amd/display/dc/dce/dce_clk_mgr.h b/drivers/gpu/drm/amd/display/dc/dce/dce_clk_mgr.h index 046077797416..3bceb31d910d 100644 --- a/drivers/gpu/drm/amd/display/dc/dce/dce_clk_mgr.h +++ b/drivers/gpu/drm/amd/display/dc/dce/dce_clk_mgr.h @@ -165,4 +165,6 @@ struct clk_mgr *dce120_clk_mgr_create(struct dc_context *ctx); void dce_clk_mgr_destroy(struct clk_mgr **clk_mgr); +int dentist_get_divider_from_did(int did); + #endif /* _DCE_CLK_MGR_H_ */ -- cgit v1.2.3 From eb6b29d62841ec38665840af4c443fbef85bf2ec Mon Sep 17 00:00:00 2001 From: Jun Lei Date: Tue, 23 Oct 2018 12:12:50 -0400 Subject: drm/amd/display: make underflow status clear explicit [why] HUBP underflow is never cleared, which causes underflow in one test to fail another test, violating the independence requirements [how] Rather than make clearing implicit, we explicitly clear underflow status in DTN. Signed-off-by: Jun Lei Reviewed-by: Tony Cheng Acked-by: Bhawanpreet Lakha Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hubp.c | 9 ++++ drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hubp.h | 3 ++ .../drm/amd/display/dc/dcn10/dcn10_hw_sequencer.c | 1 + .../drm/amd/display/dc/dcn10/dcn10_hw_sequencer.h | 2 + .../display/dc/dcn10/dcn10_hw_sequencer_debug.c | 59 +++++++++++++++++++--- drivers/gpu/drm/amd/display/dc/inc/hw/hubp.h | 1 + drivers/gpu/drm/amd/display/dc/inc/hw_sequencer.h | 1 + 7 files changed, 70 insertions(+), 6 deletions(-) (limited to 'drivers/gpu/drm') diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hubp.c b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hubp.c index 74132a1f3046..6127fd30899b 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hubp.c +++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hubp.c @@ -99,6 +99,14 @@ static unsigned int hubp1_get_underflow_status(struct hubp *hubp) return hubp_underflow; } + +void hubp1_clear_underflow(struct hubp *hubp) +{ + struct dcn10_hubp *hubp1 = TO_DCN10_HUBP(hubp); + + REG_UPDATE(DCHUBP_CNTL, HUBP_UNDERFLOW_CLEAR, 1); +} + static void hubp1_set_hubp_blank_en(struct hubp *hubp, bool blank) { struct dcn10_hubp *hubp1 = TO_DCN10_HUBP(hubp); @@ -1190,6 +1198,7 @@ static const struct hubp_funcs dcn10_hubp_funcs = { .hubp_clk_cntl = hubp1_clk_cntl, .hubp_vtg_sel = hubp1_vtg_sel, .hubp_read_state = hubp1_read_state, + .hubp_clear_underflow = hubp1_clear_underflow, .hubp_disable_control = hubp1_disable_control, .hubp_get_underflow_status = hubp1_get_underflow_status, diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hubp.h b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hubp.h index 4890273b632b..62d4232e7796 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hubp.h +++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hubp.h @@ -251,6 +251,7 @@ HUBP_SF(HUBP0_DCHUBP_CNTL, HUBP_BLANK_EN, mask_sh),\ HUBP_SF(HUBP0_DCHUBP_CNTL, HUBP_TTU_DISABLE, mask_sh),\ HUBP_SF(HUBP0_DCHUBP_CNTL, HUBP_UNDERFLOW_STATUS, mask_sh),\ + HUBP_SF(HUBP0_DCHUBP_CNTL, HUBP_UNDERFLOW_CLEAR, mask_sh),\ HUBP_SF(HUBP0_DCHUBP_CNTL, HUBP_NO_OUTSTANDING_REQ, mask_sh),\ HUBP_SF(HUBP0_DCHUBP_CNTL, HUBP_VTG_SEL, mask_sh),\ HUBP_SF(HUBP0_DCHUBP_CNTL, HUBP_DISABLE, mask_sh),\ @@ -435,6 +436,7 @@ type HUBP_NO_OUTSTANDING_REQ;\ type HUBP_VTG_SEL;\ type HUBP_UNDERFLOW_STATUS;\ + type HUBP_UNDERFLOW_CLEAR;\ type NUM_PIPES;\ type NUM_BANKS;\ type PIPE_INTERLEAVE;\ @@ -739,6 +741,7 @@ void dcn10_hubp_construct( const struct dcn_mi_mask *hubp_mask); void hubp1_read_state(struct hubp *hubp); +void hubp1_clear_underflow(struct hubp *hubp); enum cursor_pitch hubp1_get_cursor_pitch(unsigned int pitch); diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer.c b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer.c index 6b8a4da4f3c8..a59b89b27583 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer.c +++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer.c @@ -2710,6 +2710,7 @@ static const struct hw_sequencer_funcs dcn10_funcs = { .set_avmute = dce110_set_avmute, .log_hw_state = dcn10_log_hw_state, .get_hw_state = dcn10_get_hw_state, + .clear_status_bits = dcn10_clear_status_bits, .wait_for_mpcc_disconnect = dcn10_wait_for_mpcc_disconnect, .edp_backlight_control = hwss_edp_backlight_control, .edp_power_control = hwss_edp_power_control, diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer.h b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer.h index 5e5610c9e600..91bb77b468dd 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer.h +++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer.h @@ -51,6 +51,8 @@ void dcn10_get_hw_state( char *pBuf, unsigned int bufSize, unsigned int mask); +void dcn10_clear_status_bits(struct dc *dc, unsigned int mask); + bool is_lower_pipe_tree_visible(struct pipe_ctx *pipe_ctx); bool is_upper_pipe_tree_visible(struct pipe_ctx *pipe_ctx); diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer_debug.c b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer_debug.c index 64158900730f..211bb240a720 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer_debug.c +++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer_debug.c @@ -454,12 +454,6 @@ static unsigned int dcn10_get_otg_states(struct dc *dc, char *pBuf, unsigned int remaining_buffer -= chars_printed; pBuf += chars_printed; - - // Clear underflow for debug purposes - // We want to keep underflow sticky bit on for the longevity tests outside of test environment. - // This function is called only from Windows or Diags test environment, hence it's safe to clear - // it from here without affecting the original intent. - tg->funcs->clear_optc_underflow(tg); } } @@ -484,6 +478,59 @@ static unsigned int dcn10_get_clock_states(struct dc *dc, char *pBuf, unsigned i return chars_printed; } +static void dcn10_clear_otpc_underflow(struct dc *dc) +{ + struct resource_pool *pool = dc->res_pool; + int i; + + for (i = 0; i < pool->timing_generator_count; i++) { + struct timing_generator *tg = pool->timing_generators[i]; + struct dcn_otg_state s = {0}; + + optc1_read_otg_state(DCN10TG_FROM_TG(tg), &s); + + if (s.otg_enabled & 1) + tg->funcs->clear_optc_underflow(tg); + } +} + +static void dcn10_clear_hubp_underflow(struct dc *dc) +{ + struct resource_pool *pool = dc->res_pool; + int i; + + for (i = 0; i < pool->pipe_count; i++) { + struct hubp *hubp = pool->hubps[i]; + struct dcn_hubp_state *s = &(TO_DCN10_HUBP(hubp)->state); + + hubp->funcs->hubp_read_state(hubp); + + if (!s->blank_en) + hubp->funcs->hubp_clear_underflow(hubp); + } +} + +void dcn10_clear_status_bits(struct dc *dc, unsigned int mask) +{ + /* + * Mask Format + * Bit 0 - 31: Status bit to clear + * + * Mask = 0x0 means clear all status bits + */ + const unsigned int DC_HW_STATE_MASK_HUBP_UNDERFLOW = 0x1; + const unsigned int DC_HW_STATE_MASK_OTPC_UNDERFLOW = 0x2; + + if (mask == 0x0) + mask = 0xFFFFFFFF; + + if (mask & DC_HW_STATE_MASK_HUBP_UNDERFLOW) + dcn10_clear_hubp_underflow(dc); + + if (mask & DC_HW_STATE_MASK_OTPC_UNDERFLOW) + dcn10_clear_otpc_underflow(dc); +} + void dcn10_get_hw_state(struct dc *dc, char *pBuf, unsigned int bufSize, unsigned int mask) { /* diff --git a/drivers/gpu/drm/amd/display/dc/inc/hw/hubp.h b/drivers/gpu/drm/amd/display/dc/inc/hw/hubp.h index 334c48cdafdc..8f4f40646b4d 100644 --- a/drivers/gpu/drm/amd/display/dc/inc/hw/hubp.h +++ b/drivers/gpu/drm/amd/display/dc/inc/hw/hubp.h @@ -121,6 +121,7 @@ struct hubp_funcs { void (*hubp_clk_cntl)(struct hubp *hubp, bool enable); void (*hubp_vtg_sel)(struct hubp *hubp, uint32_t otg_inst); void (*hubp_read_state)(struct hubp *hubp); + void (*hubp_clear_underflow)(struct hubp *hubp); void (*hubp_disable_control)(struct hubp *hubp, bool disable_hubp); unsigned int (*hubp_get_underflow_status)(struct hubp *hubp); diff --git a/drivers/gpu/drm/amd/display/dc/inc/hw_sequencer.h b/drivers/gpu/drm/amd/display/dc/inc/hw_sequencer.h index e9b702ce02dd..d6a85f48b6d1 100644 --- a/drivers/gpu/drm/amd/display/dc/inc/hw_sequencer.h +++ b/drivers/gpu/drm/amd/display/dc/inc/hw_sequencer.h @@ -200,6 +200,7 @@ struct hw_sequencer_funcs { void (*log_hw_state)(struct dc *dc, struct dc_log_buffer_ctx *log_ctx); void (*get_hw_state)(struct dc *dc, char *pBuf, unsigned int bufSize, unsigned int mask); + void (*clear_status_bits)(struct dc *dc, unsigned int mask); void (*wait_for_mpcc_disconnect)(struct dc *dc, struct resource_pool *res_pool, -- cgit v1.2.3 From 8ce504b9389be846bcdf512ed5be8f661b3bf097 Mon Sep 17 00:00:00 2001 From: Murton Liu Date: Wed, 17 Oct 2018 14:47:45 -0400 Subject: drm/amd/display: fix gamma not being applied correctly [why] Gamma was always being set as identity on SDR monitor, leading to no changes in gamma. This caused nightlight to not apply correctly. [how] Added a default gamma structure to compare against in the sdr case. Signed-off-by: Murton Liu Reviewed-by: Krunoslav Kovac Acked-by: Bhawanpreet Lakha Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers/gpu/drm') diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer.c b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer.c index a59b89b27583..84cfe709bdc2 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer.c +++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer.c @@ -1227,7 +1227,8 @@ static bool dcn10_set_input_transfer_func(struct pipe_ctx *pipe_ctx, tf = plane_state->in_transfer_func; if (plane_state->gamma_correction && - !plane_state->gamma_correction->is_identity + !dpp_base->ctx->dc->debug.always_use_regamma + && !plane_state->gamma_correction->is_identity && dce_use_lut(plane_state->format)) dpp_base->funcs->dpp_program_input_lut(dpp_base, plane_state->gamma_correction); -- cgit v1.2.3 From 4b594b8d87cbc06602d03395c20fd1d7d216990f Mon Sep 17 00:00:00 2001 From: David Francis Date: Tue, 23 Oct 2018 13:58:39 -0400 Subject: drm/amd/display: Check for dmcu initialization before calling dmcu [Why] DMCU firmware is not required - the system is expected to run fine without it. Therefore, wherever dmcu functions could be called, dmcu initialization shoudl be checked [How] Use the helpful hook dmcu_funcs->is_dmcu_initialized Signed-off-by: David Francis Reviewed-by: Hersen Wu Acked-by: Bhawanpreet Lakha Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/display/dc/core/dc_link.c | 2 +- drivers/gpu/drm/amd/display/dc/dce/dce_clk_mgr.c | 11 +++++++---- 2 files changed, 8 insertions(+), 5 deletions(-) (limited to 'drivers/gpu/drm') diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_link.c b/drivers/gpu/drm/amd/display/dc/core/dc_link.c index 7ee9c033acbd..fe557e7142a1 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc_link.c +++ b/drivers/gpu/drm/amd/display/dc/core/dc_link.c @@ -2218,7 +2218,7 @@ bool dc_link_set_psr_enable(const struct dc_link *link, bool enable, bool wait) struct dc *core_dc = link->ctx->dc; struct dmcu *dmcu = core_dc->res_pool->dmcu; - if (dmcu != NULL && link->psr_enabled) + if ((dmcu != NULL && dmcu->funcs->is_dmcu_initialized(dmcu)) && link->psr_enabled) dmcu->funcs->set_psr_enable(dmcu, enable, wait); return true; diff --git a/drivers/gpu/drm/amd/display/dc/dce/dce_clk_mgr.c b/drivers/gpu/drm/amd/display/dc/dce/dce_clk_mgr.c index 888d7129022e..56f598567f0b 100644 --- a/drivers/gpu/drm/amd/display/dc/dce/dce_clk_mgr.c +++ b/drivers/gpu/drm/amd/display/dc/dce/dce_clk_mgr.c @@ -277,7 +277,8 @@ static int dce_set_clock( if (requested_clk_khz == 0) clk_mgr_dce->cur_min_clks_state = DM_PP_CLOCKS_STATE_NOMINAL; - dmcu->funcs->set_psr_wait_loop(dmcu, actual_clock / 1000 / 7); + if (dmcu && dmcu->funcs->is_dmcu_initialized(dmcu)) + dmcu->funcs->set_psr_wait_loop(dmcu, actual_clock / 1000 / 7); return actual_clock; } @@ -324,9 +325,11 @@ int dce112_set_clock(struct clk_mgr *clk_mgr, int requested_clk_khz) bp->funcs->set_dce_clock(bp, &dce_clk_params); if (!IS_FPGA_MAXIMUS_DC(core_dc->ctx->dce_environment)) { - if (clk_mgr_dce->dfs_bypass_disp_clk != actual_clock) - dmcu->funcs->set_psr_wait_loop(dmcu, - actual_clock / 1000 / 7); + if (dmcu && dmcu->funcs->is_dmcu_initialized(dmcu)) { + if (clk_mgr_dce->dfs_bypass_disp_clk != actual_clock) + dmcu->funcs->set_psr_wait_loop(dmcu, + actual_clock / 1000 / 7); + } } clk_mgr_dce->dfs_bypass_disp_clk = actual_clock; -- cgit v1.2.3 From 37c8f6e6a8d827673fc03e9ae30dfcff912f67ea Mon Sep 17 00:00:00 2001 From: David Francis Date: Wed, 24 Oct 2018 10:08:02 -0400 Subject: drm/amd/display: Clean up dp_blank functions [Why] Unused variable "refresh" and incorrect comment formatting [How] Remove variable, reindent comments Signed-off-by: David Francis Reviewed-by: Tony Cheng Acked-by: Bhawanpreet Lakha Signed-off-by: Alex Deucher --- .../drm/amd/display/dc/dce/dce_stream_encoder.c | 23 ++++++++++------------ .../amd/display/dc/dcn10/dcn10_stream_encoder.c | 3 --- 2 files changed, 10 insertions(+), 16 deletions(-) (limited to 'drivers/gpu/drm') diff --git a/drivers/gpu/drm/amd/display/dc/dce/dce_stream_encoder.c b/drivers/gpu/drm/amd/display/dc/dce/dce_stream_encoder.c index c47c81883d3c..cce0d18f91da 100644 --- a/drivers/gpu/drm/amd/display/dc/dce/dce_stream_encoder.c +++ b/drivers/gpu/drm/amd/display/dc/dce/dce_stream_encoder.c @@ -908,7 +908,6 @@ static void dce110_stream_encoder_dp_blank( struct stream_encoder *enc) { struct dce110_stream_encoder *enc110 = DCE110STRENC_FROM_STRENC(enc); - uint32_t retries = 0; uint32_t reg1 = 0; uint32_t max_retries = DP_BLANK_MAX_RETRY * 10; @@ -926,30 +925,28 @@ static void dce110_stream_encoder_dp_blank( * (2 = start of the next vertical blank) */ REG_UPDATE(DP_VID_STREAM_CNTL, DP_VID_STREAM_DIS_DEFER, 2); /* Larger delay to wait until VBLANK - use max retry of - * 10us*3000=30ms. This covers 16.6ms of typical 60 Hz mode + - * a little more because we may not trust delay accuracy. - */ + * 10us*3000=30ms. This covers 16.6ms of typical 60 Hz mode + + * a little more because we may not trust delay accuracy. + */ max_retries = DP_BLANK_MAX_RETRY * 150; /* disable DP stream */ REG_UPDATE(DP_VID_STREAM_CNTL, DP_VID_STREAM_ENABLE, 0); /* the encoder stops sending the video stream - * at the start of the vertical blanking. - * Poll for DP_VID_STREAM_STATUS == 0 - */ + * at the start of the vertical blanking. + * Poll for DP_VID_STREAM_STATUS == 0 + */ REG_WAIT(DP_VID_STREAM_CNTL, DP_VID_STREAM_STATUS, 0, 10, max_retries); - ASSERT(retries <= max_retries); - /* Tell the DP encoder to ignore timing from CRTC, must be done after - * the polling. If we set DP_STEER_FIFO_RESET before DP stream blank is - * complete, stream status will be stuck in video stream enabled state, - * i.e. DP_VID_STREAM_STATUS stuck at 1. - */ + * the polling. If we set DP_STEER_FIFO_RESET before DP stream blank is + * complete, stream status will be stuck in video stream enabled state, + * i.e. DP_VID_STREAM_STATUS stuck at 1. + */ REG_UPDATE(DP_STEER_FIFO, DP_STEER_FIFO_RESET, true); } diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_stream_encoder.c b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_stream_encoder.c index 6f9078f3c4d3..b8b5525a389a 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_stream_encoder.c +++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_stream_encoder.c @@ -766,7 +766,6 @@ void enc1_stream_encoder_dp_blank( struct stream_encoder *enc) { struct dcn10_stream_encoder *enc1 = DCN10STRENC_FROM_STRENC(enc); - uint32_t retries = 0; uint32_t reg1 = 0; uint32_t max_retries = DP_BLANK_MAX_RETRY * 10; @@ -803,8 +802,6 @@ void enc1_stream_encoder_dp_blank( 0, 10, max_retries); - ASSERT(retries <= max_retries); - /* Tell the DP encoder to ignore timing from CRTC, must be done after * the polling. If we set DP_STEER_FIFO_RESET before DP stream blank is * complete, stream status will be stuck in video stream enabled state, -- cgit v1.2.3 From 010c8fe9a5040f1573db647ce1930414764dbe8b Mon Sep 17 00:00:00 2001 From: Yongqiang Sun Date: Thu, 25 Oct 2018 11:32:26 -0400 Subject: drm/amd/display: Typo for return check value. [Why] Typo for return check value. [How] Correct one should be "return enable ? true : false;" Signed-off-by: Yongqiang Sun Reviewed-by: Tony Cheng Acked-by: Bhawanpreet Lakha Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hubbub.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/gpu/drm') diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hubbub.c b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hubbub.c index 4254e7e1a509..c7d1e678ebf5 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hubbub.c +++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hubbub.c @@ -100,7 +100,7 @@ bool hububu1_is_allow_self_refresh_enabled(struct hubbub *hubbub) REG_GET(DCHUBBUB_ARB_DRAM_STATE_CNTL, DCHUBBUB_ARB_ALLOW_SELF_REFRESH_FORCE_ENABLE, &enable); - return true ? false : enable; + return enable ? true : false; } -- cgit v1.2.3 From 08e1c28dd521c7b08d1b0af0bae9fb22ccc012a4 Mon Sep 17 00:00:00 2001 From: Yogesh Mohan Marimuthu Date: Sat, 20 Oct 2018 01:21:40 +0530 Subject: drm/amd/display: calculate stream->phy_pix_clk before clock mapping [why] phy_pix_clk is one of the variable used to check if one PLL can be shared with displays having common mode set configuration. As of now phy_pix_clock varialbe is calculated in function dc_validate_stream(). dc_validate_stream() function is called after clocks are assigned for the new display. Due to this during hotplug, when PLL sharing conditions are checked for new display phy_pix_clk variable will be 0 and for displays that are already enabled phy_pix_clk will have some value. Hence PLL will not be shared and if the display hardware doesn't have any more PLL to assign, mode set will fail due to resource unavailability. [how] Instead of only calculating the phy_pix_clk variable after the PLL is assigned for new display, this patch calculates phy_pix_clk also during the before assigning the PLL for new display. Signed-off-by: Yogesh Mohan Marimuthu Reviewed-by: Harry Wentland Acked-by: Bhawanpreet Lakha Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/display/dc/core/dc_resource.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers/gpu/drm') diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_resource.c b/drivers/gpu/drm/amd/display/dc/core/dc_resource.c index d09aa35f4181..98bc298ec948 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc_resource.c +++ b/drivers/gpu/drm/amd/display/dc/core/dc_resource.c @@ -1976,6 +1976,8 @@ enum dc_status resource_map_pool_resources( } */ + calculate_phy_pix_clks(stream); + /* acquire new resources */ pipe_idx = acquire_first_free_pipe(&context->res_ctx, pool, stream); -- cgit v1.2.3 From 6263f0fd0626740cb7d68fe1182f16a8b4eb6d37 Mon Sep 17 00:00:00 2001 From: Nikola Cornij Date: Thu, 25 Oct 2018 17:02:42 -0400 Subject: drm/amd/display: Consolidate two-pixels-per-container check [why] The condition to check for two pixels per containter has become rather long and is used in number of places. [how] Move the check to a helper function. Signed-off-by: Nikola Cornij Reviewed-by: Eric Bernstein Acked-by: Bhawanpreet Lakha Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/display/dc/dcn10/dcn10_optc.c | 9 +++++++-- drivers/gpu/drm/amd/display/dc/dcn10/dcn10_optc.h | 2 ++ 2 files changed, 9 insertions(+), 2 deletions(-) (limited to 'drivers/gpu/drm') diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_optc.c b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_optc.c index 7d1f66797cb3..7c76f4016ba8 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_optc.c +++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_optc.c @@ -335,9 +335,8 @@ void optc1_program_timing( /* Enable stereo - only when we need to pack 3D frame. Other types * of stereo handled in explicit call */ - h_div_2 = (dc_crtc_timing->pixel_encoding == PIXEL_ENCODING_YCBCR420) ? - 1 : 0; + h_div_2 = optc1_is_two_pixels_per_containter(&patched_crtc_timing); REG_UPDATE(OTG_H_TIMING_CNTL, OTG_H_TIMING_DIV_BY2, h_div_2); @@ -1422,3 +1421,9 @@ void dcn10_timing_generator_init(struct optc *optc1) optc1->min_h_sync_width = 8; optc1->min_v_sync_width = 1; } + +bool optc1_is_two_pixels_per_containter(const struct dc_crtc_timing *timing) +{ + return timing->pixel_encoding == PIXEL_ENCODING_YCBCR420; +} + diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_optc.h b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_optc.h index c1b114209fe8..8bacf0b6e27e 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_optc.h +++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_optc.h @@ -565,4 +565,6 @@ bool optc1_configure_crc(struct timing_generator *optc, bool optc1_get_crc(struct timing_generator *optc, uint32_t *r_cr, uint32_t *g_y, uint32_t *b_cb); +bool optc1_is_two_pixels_per_containter(const struct dc_crtc_timing *timing); + #endif /* __DC_TIMING_GENERATOR_DCN10_H__ */ -- cgit v1.2.3 From 3ce224421b66c740bb2902e69f0dd1163373842a Mon Sep 17 00:00:00 2001 From: Jun Lei Date: Wed, 24 Oct 2018 11:39:55 -0400 Subject: drm/amd/display: clear underflow on optc unblank [why] Underflow is asserted due to some timing condition which does not actually result in visible underflow (i.e. it occurs while blanked). [how] Force clear underflow occured bit whenver we unblank. Signed-off-by: Jun Lei Reviewed-by: Tony Cheng Acked-by: Aric Cyr Acked-by: Bhawanpreet Lakha Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/display/dc/dcn10/dcn10_optc.c | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) (limited to 'drivers/gpu/drm') diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_optc.c b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_optc.c index 7c76f4016ba8..7c138615f17d 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_optc.c +++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_optc.c @@ -359,20 +359,19 @@ void optc1_set_blank_data_double_buffer(struct timing_generator *optc, bool enab static void optc1_unblank_crtc(struct timing_generator *optc) { struct optc *optc1 = DCN10TG_FROM_TG(optc); - uint32_t vertical_interrupt_enable = 0; - - REG_GET(OTG_VERTICAL_INTERRUPT2_CONTROL, - OTG_VERTICAL_INTERRUPT2_INT_ENABLE, &vertical_interrupt_enable); - - /* temporary work around for vertical interrupt, once vertical interrupt enabled, - * this check will be removed. - */ - if (vertical_interrupt_enable) - optc1_set_blank_data_double_buffer(optc, true); REG_UPDATE_2(OTG_BLANK_CONTROL, OTG_BLANK_DATA_EN, 0, OTG_BLANK_DE_MODE, 0); + + /* W/A for automated testing + * Automated testing will fail underflow test as there + * sporadic underflows which occur during the optc blank + * sequence. As a w/a, clear underflow on unblank. + * This prevents the failure, but will not mask actual + * underflow that affect real use cases. + */ + optc1_clear_optc_underflow(optc); } /** -- cgit v1.2.3 From 9b6067c08de84215d4c66a74150e9ac3e9f0ef72 Mon Sep 17 00:00:00 2001 From: Dmytro Laktyushkin Date: Fri, 19 Oct 2018 16:17:29 -0400 Subject: drm/amd/display: redesign scaling rotation math Change the math to work in viewport rotation when calculating viewport and viewport adjustment. This simplifies the math for viewport calculation and makes viewport adjustment easier to understand. Signed-off-by: Dmytro Laktyushkin Reviewed-by: Tony Cheng Acked-by: Bhawanpreet Lakha Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/display/dc/core/dc_resource.c | 654 ++++++++-------------- 1 file changed, 240 insertions(+), 414 deletions(-) (limited to 'drivers/gpu/drm') diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_resource.c b/drivers/gpu/drm/amd/display/dc/core/dc_resource.c index 98bc298ec948..0a1985ca9882 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc_resource.c +++ b/drivers/gpu/drm/amd/display/dc/core/dc_resource.c @@ -478,10 +478,29 @@ static enum pixel_format convert_pixel_format_to_dalsurface( return dal_pixel_format; } -static void rect_swap_helper(struct rect *rect) -{ - swap(rect->height, rect->width); - swap(rect->x, rect->y); +static inline void get_vp_scan_direction( + enum dc_rotation_angle rotation, + bool horizontal_mirror, + bool *orthogonal_rotation, + bool *flip_vert_scan_dir, + bool *flip_horz_scan_dir) +{ + *orthogonal_rotation = false; + *flip_vert_scan_dir = false; + *flip_horz_scan_dir = false; + if (rotation == ROTATION_ANGLE_180) { + *flip_vert_scan_dir = true; + *flip_horz_scan_dir = true; + } else if (rotation == ROTATION_ANGLE_90) { + *orthogonal_rotation = true; + *flip_horz_scan_dir = true; + } else if (rotation == ROTATION_ANGLE_270) { + *orthogonal_rotation = true; + *flip_vert_scan_dir = true; + } + + if (horizontal_mirror) + *flip_horz_scan_dir = !*flip_horz_scan_dir; } static void calculate_viewport(struct pipe_ctx *pipe_ctx) @@ -490,33 +509,14 @@ static void calculate_viewport(struct pipe_ctx *pipe_ctx) const struct dc_stream_state *stream = pipe_ctx->stream; struct scaler_data *data = &pipe_ctx->plane_res.scl_data; struct rect surf_src = plane_state->src_rect; - struct rect clip = { 0 }; + struct rect clip, dest; int vpc_div = (data->format == PIXEL_FORMAT_420BPP8 || data->format == PIXEL_FORMAT_420BPP10) ? 2 : 1; bool pri_split = pipe_ctx->bottom_pipe && pipe_ctx->bottom_pipe->plane_state == pipe_ctx->plane_state; bool sec_split = pipe_ctx->top_pipe && pipe_ctx->top_pipe->plane_state == pipe_ctx->plane_state; - bool flip_vert_scan_dir = false, flip_horz_scan_dir = false; - - - /* - * We need take horizontal mirror into account. On an unrotated surface this means - * that the viewport offset is actually the offset from the other side of source - * image so we have to subtract the right edge of the viewport from the right edge of - * the source window. Similar to mirror we need to take into account how offset is - * affected for 270/180 rotations - */ - if (pipe_ctx->plane_state->rotation == ROTATION_ANGLE_180) { - flip_vert_scan_dir = true; - flip_horz_scan_dir = true; - } else if (pipe_ctx->plane_state->rotation == ROTATION_ANGLE_90) - flip_vert_scan_dir = true; - else if (pipe_ctx->plane_state->rotation == ROTATION_ANGLE_270) - flip_horz_scan_dir = true; - - if (pipe_ctx->plane_state->horizontal_mirror) - flip_horz_scan_dir = !flip_horz_scan_dir; + bool orthogonal_rotation, flip_y_start, flip_x_start; if (stream->view_format == VIEW_3D_FORMAT_SIDE_BY_SIDE || stream->view_format == VIEW_3D_FORMAT_TOP_AND_BOTTOM) { @@ -524,13 +524,10 @@ static void calculate_viewport(struct pipe_ctx *pipe_ctx) sec_split = false; } - if (pipe_ctx->plane_state->rotation == ROTATION_ANGLE_90 || - pipe_ctx->plane_state->rotation == ROTATION_ANGLE_270) - rect_swap_helper(&surf_src); - /* The actual clip is an intersection between stream * source and surface clip */ + dest = plane_state->dst_rect; clip.x = stream->src.x > plane_state->clip_rect.x ? stream->src.x : plane_state->clip_rect.x; @@ -547,66 +544,77 @@ static void calculate_viewport(struct pipe_ctx *pipe_ctx) stream->src.y + stream->src.height - clip.y : plane_state->clip_rect.y + plane_state->clip_rect.height - clip.y ; - /* offset = surf_src.ofs + (clip.ofs - surface->dst_rect.ofs) * scl_ratio - * note: surf_src.ofs should be added after rotation/mirror offset direction - * adjustment since it is already in viewport space - * num_pixels = clip.num_pix * scl_ratio + /* + * Need to calculate how scan origin is shifted in vp space + * to correctly rotate clip and dst */ - data->viewport.x = (clip.x - plane_state->dst_rect.x) * - surf_src.width / plane_state->dst_rect.width; - data->viewport.width = clip.width * - surf_src.width / plane_state->dst_rect.width; + get_vp_scan_direction( + plane_state->rotation, + plane_state->horizontal_mirror, + &orthogonal_rotation, + &flip_y_start, + &flip_x_start); - data->viewport.y = (clip.y - plane_state->dst_rect.y) * - surf_src.height / plane_state->dst_rect.height; - data->viewport.height = clip.height * - surf_src.height / plane_state->dst_rect.height; - - if (flip_vert_scan_dir) - data->viewport.y = surf_src.height - data->viewport.y - data->viewport.height; - if (flip_horz_scan_dir) - data->viewport.x = surf_src.width - data->viewport.x - data->viewport.width; + if (orthogonal_rotation) { + swap(clip.x, clip.y); + swap(clip.width, clip.height); + swap(dest.x, dest.y); + swap(dest.width, dest.height); + } + if (flip_x_start) { + clip.x = dest.x + dest.width - clip.x - clip.width; + dest.x = 0; + } + if (flip_y_start) { + clip.y = dest.y + dest.height - clip.y - clip.height; + dest.y = 0; + } - data->viewport.x += surf_src.x; - data->viewport.y += surf_src.y; + /* offset = surf_src.ofs + (clip.ofs - surface->dst_rect.ofs) * scl_ratio + * num_pixels = clip.num_pix * scl_ratio + */ + data->viewport.x = surf_src.x + (clip.x - dest.x) * surf_src.width / dest.width; + data->viewport.width = clip.width * surf_src.width / dest.width; + + data->viewport.y = surf_src.y + (clip.y - dest.y) * surf_src.height / dest.height; + data->viewport.height = clip.height * surf_src.height / dest.height; + + /* Handle split */ + if (pri_split || sec_split) { + if (orthogonal_rotation) { + if (flip_y_start != pri_split) + data->viewport.height /= 2; + else { + data->viewport.y += data->viewport.height / 2; + /* Ceil offset pipe */ + data->viewport.height = (data->viewport.height + 1) / 2; + } + } else { + if (flip_x_start != pri_split) + data->viewport.width /= 2; + else { + data->viewport.x += data->viewport.width / 2; + /* Ceil offset pipe */ + data->viewport.width = (data->viewport.width + 1) / 2; + } + } + } /* Round down, compensate in init */ data->viewport_c.x = data->viewport.x / vpc_div; data->viewport_c.y = data->viewport.y / vpc_div; - data->inits.h_c = (data->viewport.x % vpc_div) != 0 ? - dc_fixpt_half : dc_fixpt_zero; - data->inits.v_c = (data->viewport.y % vpc_div) != 0 ? - dc_fixpt_half : dc_fixpt_zero; + data->inits.h_c = (data->viewport.x % vpc_div) != 0 ? dc_fixpt_half : dc_fixpt_zero; + data->inits.v_c = (data->viewport.y % vpc_div) != 0 ? dc_fixpt_half : dc_fixpt_zero; + /* Round up, assume original video size always even dimensions */ data->viewport_c.width = (data->viewport.width + vpc_div - 1) / vpc_div; data->viewport_c.height = (data->viewport.height + vpc_div - 1) / vpc_div; - - /* Handle hsplit */ - if (sec_split) { - data->viewport.x += data->viewport.width / 2; - data->viewport_c.x += data->viewport_c.width / 2; - /* Ceil offset pipe */ - data->viewport.width = (data->viewport.width + 1) / 2; - data->viewport_c.width = (data->viewport_c.width + 1) / 2; - } else if (pri_split) { - if (data->viewport.width > 1) - data->viewport.width /= 2; - if (data->viewport_c.width > 1) - data->viewport_c.width /= 2; - } - - if (plane_state->rotation == ROTATION_ANGLE_90 || - plane_state->rotation == ROTATION_ANGLE_270) { - rect_swap_helper(&data->viewport_c); - rect_swap_helper(&data->viewport); - } } -static void calculate_recout(struct pipe_ctx *pipe_ctx, struct rect *recout_full) +static void calculate_recout(struct pipe_ctx *pipe_ctx) { const struct dc_plane_state *plane_state = pipe_ctx->plane_state; const struct dc_stream_state *stream = pipe_ctx->stream; - struct rect surf_src = plane_state->src_rect; struct rect surf_clip = plane_state->clip_rect; bool pri_split = pipe_ctx->bottom_pipe && pipe_ctx->bottom_pipe->plane_state == pipe_ctx->plane_state; @@ -614,10 +622,6 @@ static void calculate_recout(struct pipe_ctx *pipe_ctx, struct rect *recout_full pipe_ctx->top_pipe->plane_state == pipe_ctx->plane_state; bool top_bottom_split = stream->view_format == VIEW_3D_FORMAT_TOP_AND_BOTTOM; - if (pipe_ctx->plane_state->rotation == ROTATION_ANGLE_90 || - pipe_ctx->plane_state->rotation == ROTATION_ANGLE_270) - rect_swap_helper(&surf_src); - pipe_ctx->plane_res.scl_data.recout.x = stream->dst.x; if (stream->src.x < surf_clip.x) pipe_ctx->plane_res.scl_data.recout.x += (surf_clip.x @@ -646,7 +650,7 @@ static void calculate_recout(struct pipe_ctx *pipe_ctx, struct rect *recout_full stream->dst.y + stream->dst.height - pipe_ctx->plane_res.scl_data.recout.y; - /* Handle h & vsplit */ + /* Handle h & v split, handle rotation using viewport */ if (sec_split && top_bottom_split) { pipe_ctx->plane_res.scl_data.recout.y += pipe_ctx->plane_res.scl_data.recout.height / 2; @@ -655,44 +659,14 @@ static void calculate_recout(struct pipe_ctx *pipe_ctx, struct rect *recout_full (pipe_ctx->plane_res.scl_data.recout.height + 1) / 2; } else if (pri_split && top_bottom_split) pipe_ctx->plane_res.scl_data.recout.height /= 2; - else if (pri_split || sec_split) { - /* HMirror XOR Secondary_pipe XOR Rotation_180 */ - bool right_view = (sec_split != plane_state->horizontal_mirror) != - (plane_state->rotation == ROTATION_ANGLE_180); - - if (plane_state->rotation == ROTATION_ANGLE_90 - || plane_state->rotation == ROTATION_ANGLE_270) - /* Secondary_pipe XOR Rotation_270 */ - right_view = (plane_state->rotation == ROTATION_ANGLE_270) != sec_split; - - if (right_view) { - pipe_ctx->plane_res.scl_data.recout.x += - pipe_ctx->plane_res.scl_data.recout.width / 2; - /* Ceil offset pipe */ - pipe_ctx->plane_res.scl_data.recout.width = - (pipe_ctx->plane_res.scl_data.recout.width + 1) / 2; - } else { - if (pipe_ctx->plane_res.scl_data.recout.width > 1) - pipe_ctx->plane_res.scl_data.recout.width /= 2; - } - } - /* Unclipped recout offset = stream dst offset + ((surf dst offset - stream surf_src offset) - * * 1/ stream scaling ratio) - (surf surf_src offset * 1/ full scl - * ratio) - */ - recout_full->x = stream->dst.x + (plane_state->dst_rect.x - stream->src.x) - * stream->dst.width / stream->src.width - - surf_src.x * plane_state->dst_rect.width / surf_src.width - * stream->dst.width / stream->src.width; - recout_full->y = stream->dst.y + (plane_state->dst_rect.y - stream->src.y) - * stream->dst.height / stream->src.height - - surf_src.y * plane_state->dst_rect.height / surf_src.height - * stream->dst.height / stream->src.height; - - recout_full->width = plane_state->dst_rect.width - * stream->dst.width / stream->src.width; - recout_full->height = plane_state->dst_rect.height - * stream->dst.height / stream->src.height; + else if (sec_split) { + pipe_ctx->plane_res.scl_data.recout.x += + pipe_ctx->plane_res.scl_data.recout.width / 2; + /* Ceil offset pipe */ + pipe_ctx->plane_res.scl_data.recout.width = + (pipe_ctx->plane_res.scl_data.recout.width + 1) / 2; + } else if (pri_split) + pipe_ctx->plane_res.scl_data.recout.width /= 2; } static void calculate_scaling_ratios(struct pipe_ctx *pipe_ctx) @@ -705,9 +679,10 @@ static void calculate_scaling_ratios(struct pipe_ctx *pipe_ctx) const int out_w = stream->dst.width; const int out_h = stream->dst.height; + /*Swap surf_src height and width since scaling ratios are in recout rotation*/ if (pipe_ctx->plane_state->rotation == ROTATION_ANGLE_90 || pipe_ctx->plane_state->rotation == ROTATION_ANGLE_270) - rect_swap_helper(&surf_src); + swap(surf_src.height, surf_src.width); pipe_ctx->plane_res.scl_data.ratios.horz = dc_fixpt_from_fraction( surf_src.width, @@ -744,351 +719,202 @@ static void calculate_scaling_ratios(struct pipe_ctx *pipe_ctx) pipe_ctx->plane_res.scl_data.ratios.vert_c, 19); } -static void calculate_inits_and_adj_vp(struct pipe_ctx *pipe_ctx, struct rect *recout_full) +static inline void adjust_vp_and_init_for_seamless_clip( + bool flip_scan_dir, + int recout_skip, + int src_size, + int taps, + struct fixed31_32 ratio, + struct fixed31_32 *init, + int *vp_offset, + int *vp_size) { - struct scaler_data *data = &pipe_ctx->plane_res.scl_data; - struct rect src = pipe_ctx->plane_state->src_rect; - int vpc_div = (data->format == PIXEL_FORMAT_420BPP8 - || data->format == PIXEL_FORMAT_420BPP10) ? 2 : 1; - bool flip_vert_scan_dir = false, flip_horz_scan_dir = false; - - /* - * Need to calculate the scan direction for viewport to make adjustments - */ - if (pipe_ctx->plane_state->rotation == ROTATION_ANGLE_180) { - flip_vert_scan_dir = true; - flip_horz_scan_dir = true; - } else if (pipe_ctx->plane_state->rotation == ROTATION_ANGLE_90) - flip_vert_scan_dir = true; - else if (pipe_ctx->plane_state->rotation == ROTATION_ANGLE_270) - flip_horz_scan_dir = true; - - if (pipe_ctx->plane_state->horizontal_mirror) - flip_horz_scan_dir = !flip_horz_scan_dir; - - if (pipe_ctx->plane_state->rotation == ROTATION_ANGLE_90 || - pipe_ctx->plane_state->rotation == ROTATION_ANGLE_270) { - rect_swap_helper(&src); - rect_swap_helper(&data->viewport_c); - rect_swap_helper(&data->viewport); - } - - /* - * Init calculated according to formula: - * init = (scaling_ratio + number_of_taps + 1) / 2 - * init_bot = init + scaling_ratio - * init_c = init + truncated_vp_c_offset(from calculate viewport) - */ - data->inits.h = dc_fixpt_truncate(dc_fixpt_div_int( - dc_fixpt_add_int(data->ratios.horz, data->taps.h_taps + 1), 2), 19); - - data->inits.h_c = dc_fixpt_truncate(dc_fixpt_add(data->inits.h_c, dc_fixpt_div_int( - dc_fixpt_add_int(data->ratios.horz_c, data->taps.h_taps_c + 1), 2)), 19); - - data->inits.v = dc_fixpt_truncate(dc_fixpt_div_int( - dc_fixpt_add_int(data->ratios.vert, data->taps.v_taps + 1), 2), 19); - - data->inits.v_c = dc_fixpt_truncate(dc_fixpt_add(data->inits.v_c, dc_fixpt_div_int( - dc_fixpt_add_int(data->ratios.vert_c, data->taps.v_taps_c + 1), 2)), 19); - - if (!flip_horz_scan_dir) { + if (!flip_scan_dir) { /* Adjust for viewport end clip-off */ - if ((data->viewport.x + data->viewport.width) < (src.x + src.width)) { - int vp_clip = src.x + src.width - data->viewport.width - data->viewport.x; - int int_part = dc_fixpt_floor( - dc_fixpt_sub(data->inits.h, data->ratios.horz)); - - int_part = int_part > 0 ? int_part : 0; - data->viewport.width += int_part < vp_clip ? int_part : vp_clip; - } - if ((data->viewport_c.x + data->viewport_c.width) < (src.x + src.width) / vpc_div) { - int vp_clip = (src.x + src.width) / vpc_div - - data->viewport_c.width - data->viewport_c.x; - int int_part = dc_fixpt_floor( - dc_fixpt_sub(data->inits.h_c, data->ratios.horz_c)); + if ((*vp_offset + *vp_size) < src_size) { + int vp_clip = src_size - *vp_size - *vp_offset; + int int_part = dc_fixpt_floor(dc_fixpt_sub(*init, ratio)); int_part = int_part > 0 ? int_part : 0; - data->viewport_c.width += int_part < vp_clip ? int_part : vp_clip; + *vp_size += int_part < vp_clip ? int_part : vp_clip; } /* Adjust for non-0 viewport offset */ - if (data->viewport.x) { + if (*vp_offset) { int int_part; - data->inits.h = dc_fixpt_add(data->inits.h, dc_fixpt_mul_int( - data->ratios.horz, data->recout.x - recout_full->x)); - int_part = dc_fixpt_floor(data->inits.h) - data->viewport.x; - if (int_part < data->taps.h_taps) { - int int_adj = data->viewport.x >= (data->taps.h_taps - int_part) ? - (data->taps.h_taps - int_part) : data->viewport.x; - data->viewport.x -= int_adj; - data->viewport.width += int_adj; + *init = dc_fixpt_add(*init, dc_fixpt_mul_int(ratio, recout_skip)); + int_part = dc_fixpt_floor(*init) - *vp_offset; + if (int_part < taps) { + int int_adj = *vp_offset >= (taps - int_part) ? + (taps - int_part) : *vp_offset; + *vp_offset -= int_adj; + *vp_size += int_adj; int_part += int_adj; - } else if (int_part > data->taps.h_taps) { - data->viewport.x += int_part - data->taps.h_taps; - data->viewport.width -= int_part - data->taps.h_taps; - int_part = data->taps.h_taps; + } else if (int_part > taps) { + *vp_offset += int_part - taps; + *vp_size -= int_part - taps; + int_part = taps; } - data->inits.h.value &= 0xffffffff; - data->inits.h = dc_fixpt_add_int(data->inits.h, int_part); - } - - if (data->viewport_c.x) { - int int_part; - - data->inits.h_c = dc_fixpt_add(data->inits.h_c, dc_fixpt_mul_int( - data->ratios.horz_c, data->recout.x - recout_full->x)); - int_part = dc_fixpt_floor(data->inits.h_c) - data->viewport_c.x; - if (int_part < data->taps.h_taps_c) { - int int_adj = data->viewport_c.x >= (data->taps.h_taps_c - int_part) ? - (data->taps.h_taps_c - int_part) : data->viewport_c.x; - data->viewport_c.x -= int_adj; - data->viewport_c.width += int_adj; - int_part += int_adj; - } else if (int_part > data->taps.h_taps_c) { - data->viewport_c.x += int_part - data->taps.h_taps_c; - data->viewport_c.width -= int_part - data->taps.h_taps_c; - int_part = data->taps.h_taps_c; - } - data->inits.h_c.value &= 0xffffffff; - data->inits.h_c = dc_fixpt_add_int(data->inits.h_c, int_part); + init->value &= 0xffffffff; + *init = dc_fixpt_add_int(*init, int_part); } } else { /* Adjust for non-0 viewport offset */ - if (data->viewport.x) { - int int_part = dc_fixpt_floor( - dc_fixpt_sub(data->inits.h, data->ratios.horz)); - - int_part = int_part > 0 ? int_part : 0; - data->viewport.width += int_part < data->viewport.x ? int_part : data->viewport.x; - data->viewport.x -= int_part < data->viewport.x ? int_part : data->viewport.x; - } - if (data->viewport_c.x) { - int int_part = dc_fixpt_floor( - dc_fixpt_sub(data->inits.h_c, data->ratios.horz_c)); + if (*vp_offset) { + int int_part = dc_fixpt_floor(dc_fixpt_sub(*init, ratio)); int_part = int_part > 0 ? int_part : 0; - data->viewport_c.width += int_part < data->viewport_c.x ? int_part : data->viewport_c.x; - data->viewport_c.x -= int_part < data->viewport_c.x ? int_part : data->viewport_c.x; + *vp_size += int_part < *vp_offset ? int_part : *vp_offset; + *vp_offset -= int_part < *vp_offset ? int_part : *vp_offset; } /* Adjust for viewport end clip-off */ - if ((data->viewport.x + data->viewport.width) < (src.x + src.width)) { + if ((*vp_offset + *vp_size) < src_size) { int int_part; - int end_offset = src.x + src.width - - data->viewport.x - data->viewport.width; + int end_offset = src_size - *vp_offset - *vp_size; /* * this is init if vp had no offset, keep in mind this is from the * right side of vp due to scan direction */ - data->inits.h = dc_fixpt_add(data->inits.h, dc_fixpt_mul_int( - data->ratios.horz, data->recout.x - recout_full->x)); + *init = dc_fixpt_add(*init, dc_fixpt_mul_int(ratio, recout_skip)); /* * this is the difference between first pixel of viewport available to read * and init position, takning into account scan direction */ - int_part = dc_fixpt_floor(data->inits.h) - end_offset; - if (int_part < data->taps.h_taps) { - int int_adj = end_offset >= (data->taps.h_taps - int_part) ? - (data->taps.h_taps - int_part) : end_offset; - data->viewport.width += int_adj; + int_part = dc_fixpt_floor(*init) - end_offset; + if (int_part < taps) { + int int_adj = end_offset >= (taps - int_part) ? + (taps - int_part) : end_offset; + *vp_size += int_adj; int_part += int_adj; - } else if (int_part > data->taps.h_taps) { - data->viewport.width += int_part - data->taps.h_taps; - int_part = data->taps.h_taps; + } else if (int_part > taps) { + *vp_size += int_part - taps; + int_part = taps; } - data->inits.h.value &= 0xffffffff; - data->inits.h = dc_fixpt_add_int(data->inits.h, int_part); + init->value &= 0xffffffff; + *init = dc_fixpt_add_int(*init, int_part); } - - if ((data->viewport_c.x + data->viewport_c.width) < (src.x + src.width) / vpc_div) { - int int_part; - int end_offset = (src.x + src.width) / vpc_div - - data->viewport_c.x - data->viewport_c.width; - - /* - * this is init if vp had no offset, keep in mind this is from the - * right side of vp due to scan direction - */ - data->inits.h_c = dc_fixpt_add(data->inits.h_c, dc_fixpt_mul_int( - data->ratios.horz_c, data->recout.x - recout_full->x)); - /* - * this is the difference between first pixel of viewport available to read - * and init position, takning into account scan direction - */ - int_part = dc_fixpt_floor(data->inits.h_c) - end_offset; - if (int_part < data->taps.h_taps_c) { - int int_adj = end_offset >= (data->taps.h_taps_c - int_part) ? - (data->taps.h_taps_c - int_part) : end_offset; - data->viewport_c.width += int_adj; - int_part += int_adj; - } else if (int_part > data->taps.h_taps_c) { - data->viewport_c.width += int_part - data->taps.h_taps_c; - int_part = data->taps.h_taps_c; - } - data->inits.h_c.value &= 0xffffffff; - data->inits.h_c = dc_fixpt_add_int(data->inits.h_c, int_part); - } - } - if (!flip_vert_scan_dir) { - /* Adjust for viewport end clip-off */ - if ((data->viewport.y + data->viewport.height) < (src.y + src.height)) { - int vp_clip = src.y + src.height - data->viewport.height - data->viewport.y; - int int_part = dc_fixpt_floor( - dc_fixpt_sub(data->inits.v, data->ratios.vert)); - - int_part = int_part > 0 ? int_part : 0; - data->viewport.height += int_part < vp_clip ? int_part : vp_clip; - } - if ((data->viewport_c.y + data->viewport_c.height) < (src.y + src.height) / vpc_div) { - int vp_clip = (src.y + src.height) / vpc_div - - data->viewport_c.height - data->viewport_c.y; - int int_part = dc_fixpt_floor( - dc_fixpt_sub(data->inits.v_c, data->ratios.vert_c)); - - int_part = int_part > 0 ? int_part : 0; - data->viewport_c.height += int_part < vp_clip ? int_part : vp_clip; - } - - /* Adjust for non-0 viewport offset */ - if (data->viewport.y) { - int int_part; - - data->inits.v = dc_fixpt_add(data->inits.v, dc_fixpt_mul_int( - data->ratios.vert, data->recout.y - recout_full->y)); - int_part = dc_fixpt_floor(data->inits.v) - data->viewport.y; - if (int_part < data->taps.v_taps) { - int int_adj = data->viewport.y >= (data->taps.v_taps - int_part) ? - (data->taps.v_taps - int_part) : data->viewport.y; - data->viewport.y -= int_adj; - data->viewport.height += int_adj; - int_part += int_adj; - } else if (int_part > data->taps.v_taps) { - data->viewport.y += int_part - data->taps.v_taps; - data->viewport.height -= int_part - data->taps.v_taps; - int_part = data->taps.v_taps; - } - data->inits.v.value &= 0xffffffff; - data->inits.v = dc_fixpt_add_int(data->inits.v, int_part); - } - - if (data->viewport_c.y) { - int int_part; +} - data->inits.v_c = dc_fixpt_add(data->inits.v_c, dc_fixpt_mul_int( - data->ratios.vert_c, data->recout.y - recout_full->y)); - int_part = dc_fixpt_floor(data->inits.v_c) - data->viewport_c.y; - if (int_part < data->taps.v_taps_c) { - int int_adj = data->viewport_c.y >= (data->taps.v_taps_c - int_part) ? - (data->taps.v_taps_c - int_part) : data->viewport_c.y; - data->viewport_c.y -= int_adj; - data->viewport_c.height += int_adj; - int_part += int_adj; - } else if (int_part > data->taps.v_taps_c) { - data->viewport_c.y += int_part - data->taps.v_taps_c; - data->viewport_c.height -= int_part - data->taps.v_taps_c; - int_part = data->taps.v_taps_c; - } - data->inits.v_c.value &= 0xffffffff; - data->inits.v_c = dc_fixpt_add_int(data->inits.v_c, int_part); - } - } else { - /* Adjust for non-0 viewport offset */ - if (data->viewport.y) { - int int_part = dc_fixpt_floor( - dc_fixpt_sub(data->inits.v, data->ratios.vert)); +static void calculate_inits_and_adj_vp(struct pipe_ctx *pipe_ctx) +{ + const struct dc_plane_state *plane_state = pipe_ctx->plane_state; + const struct dc_stream_state *stream = pipe_ctx->stream; + struct scaler_data *data = &pipe_ctx->plane_res.scl_data; + struct rect src = pipe_ctx->plane_state->src_rect; + int recout_skip_h, recout_skip_v, surf_size_h, surf_size_v; + int vpc_div = (data->format == PIXEL_FORMAT_420BPP8 + || data->format == PIXEL_FORMAT_420BPP10) ? 2 : 1; + bool orthogonal_rotation, flip_vert_scan_dir, flip_horz_scan_dir; - int_part = int_part > 0 ? int_part : 0; - data->viewport.height += int_part < data->viewport.y ? int_part : data->viewport.y; - data->viewport.y -= int_part < data->viewport.y ? int_part : data->viewport.y; - } - if (data->viewport_c.y) { - int int_part = dc_fixpt_floor( - dc_fixpt_sub(data->inits.v_c, data->ratios.vert_c)); + /* + * Need to calculate the scan direction for viewport to make adjustments + */ + get_vp_scan_direction( + plane_state->rotation, + plane_state->horizontal_mirror, + &orthogonal_rotation, + &flip_vert_scan_dir, + &flip_horz_scan_dir); + + /* Calculate src rect rotation adjusted to recout space */ + surf_size_h = src.x + src.width; + surf_size_v = src.y + src.height; + if (flip_horz_scan_dir) + src.x = 0; + if (flip_vert_scan_dir) + src.y = 0; + if (orthogonal_rotation) { + swap(src.x, src.y); + swap(src.width, src.height); + } - int_part = int_part > 0 ? int_part : 0; - data->viewport_c.height += int_part < data->viewport_c.y ? int_part : data->viewport_c.y; - data->viewport_c.y -= int_part < data->viewport_c.y ? int_part : data->viewport_c.y; - } + /* Recout matching initial vp offset = recout_offset - (stream dst offset + + * ((surf dst offset - stream src offset) * 1/ stream scaling ratio) + * - (surf surf_src offset * 1/ full scl ratio)) + */ + recout_skip_h = data->recout.x - (stream->dst.x + (plane_state->dst_rect.x - stream->src.x) + * stream->dst.width / stream->src.width - + src.x * plane_state->dst_rect.width / src.width + * stream->dst.width / stream->src.width); + recout_skip_v = data->recout.y - (stream->dst.y + (plane_state->dst_rect.y - stream->src.y) + * stream->dst.height / stream->src.height - + src.y * plane_state->dst_rect.height / src.height + * stream->dst.height / stream->src.height); + if (orthogonal_rotation) + swap(recout_skip_h, recout_skip_v); + /* + * Init calculated according to formula: + * init = (scaling_ratio + number_of_taps + 1) / 2 + * init_bot = init + scaling_ratio + * init_c = init + truncated_vp_c_offset(from calculate viewport) + */ + data->inits.h = dc_fixpt_truncate(dc_fixpt_div_int( + dc_fixpt_add_int(data->ratios.horz, data->taps.h_taps + 1), 2), 19); - /* Adjust for viewport end clip-off */ - if ((data->viewport.y + data->viewport.height) < (src.y + src.height)) { - int int_part; - int end_offset = src.y + src.height - - data->viewport.y - data->viewport.height; + data->inits.h_c = dc_fixpt_truncate(dc_fixpt_add(data->inits.h_c, dc_fixpt_div_int( + dc_fixpt_add_int(data->ratios.horz_c, data->taps.h_taps_c + 1), 2)), 19); - /* - * this is init if vp had no offset, keep in mind this is from the - * right side of vp due to scan direction - */ - data->inits.v = dc_fixpt_add(data->inits.v, dc_fixpt_mul_int( - data->ratios.vert, data->recout.y - recout_full->y)); - /* - * this is the difference between first pixel of viewport available to read - * and init position, taking into account scan direction - */ - int_part = dc_fixpt_floor(data->inits.v) - end_offset; - if (int_part < data->taps.v_taps) { - int int_adj = end_offset >= (data->taps.v_taps - int_part) ? - (data->taps.v_taps - int_part) : end_offset; - data->viewport.height += int_adj; - int_part += int_adj; - } else if (int_part > data->taps.v_taps) { - data->viewport.height += int_part - data->taps.v_taps; - int_part = data->taps.v_taps; - } - data->inits.v.value &= 0xffffffff; - data->inits.v = dc_fixpt_add_int(data->inits.v, int_part); - } + data->inits.v = dc_fixpt_truncate(dc_fixpt_div_int( + dc_fixpt_add_int(data->ratios.vert, data->taps.v_taps + 1), 2), 19); - if ((data->viewport_c.y + data->viewport_c.height) < (src.y + src.height) / vpc_div) { - int int_part; - int end_offset = (src.y + src.height) / vpc_div - - data->viewport_c.y - data->viewport_c.height; + data->inits.v_c = dc_fixpt_truncate(dc_fixpt_add(data->inits.v_c, dc_fixpt_div_int( + dc_fixpt_add_int(data->ratios.vert_c, data->taps.v_taps_c + 1), 2)), 19); - /* - * this is init if vp had no offset, keep in mind this is from the - * right side of vp due to scan direction - */ - data->inits.v_c = dc_fixpt_add(data->inits.v_c, dc_fixpt_mul_int( - data->ratios.vert_c, data->recout.y - recout_full->y)); - /* - * this is the difference between first pixel of viewport available to read - * and init position, taking into account scan direction - */ - int_part = dc_fixpt_floor(data->inits.v_c) - end_offset; - if (int_part < data->taps.v_taps_c) { - int int_adj = end_offset >= (data->taps.v_taps_c - int_part) ? - (data->taps.v_taps_c - int_part) : end_offset; - data->viewport_c.height += int_adj; - int_part += int_adj; - } else if (int_part > data->taps.v_taps_c) { - data->viewport_c.height += int_part - data->taps.v_taps_c; - int_part = data->taps.v_taps_c; - } - data->inits.v_c.value &= 0xffffffff; - data->inits.v_c = dc_fixpt_add_int(data->inits.v_c, int_part); - } - } + /* + * Taps, inits and scaling ratios are in recout space need to rotate + * to viewport rotation before adjustment + */ + adjust_vp_and_init_for_seamless_clip( + flip_horz_scan_dir, + recout_skip_h, + surf_size_h, + orthogonal_rotation ? data->taps.v_taps : data->taps.h_taps, + orthogonal_rotation ? data->ratios.vert : data->ratios.horz, + orthogonal_rotation ? &data->inits.v : &data->inits.h, + &data->viewport.x, + &data->viewport.width); + adjust_vp_and_init_for_seamless_clip( + flip_horz_scan_dir, + recout_skip_h, + surf_size_h / vpc_div, + orthogonal_rotation ? data->taps.v_taps_c : data->taps.h_taps_c, + orthogonal_rotation ? data->ratios.vert_c : data->ratios.horz_c, + orthogonal_rotation ? &data->inits.v_c : &data->inits.h_c, + &data->viewport_c.x, + &data->viewport_c.width); + adjust_vp_and_init_for_seamless_clip( + flip_vert_scan_dir, + recout_skip_v, + surf_size_v, + orthogonal_rotation ? data->taps.h_taps : data->taps.v_taps, + orthogonal_rotation ? data->ratios.horz : data->ratios.vert, + orthogonal_rotation ? &data->inits.h : &data->inits.v, + &data->viewport.y, + &data->viewport.height); + adjust_vp_and_init_for_seamless_clip( + flip_vert_scan_dir, + recout_skip_v, + surf_size_v / vpc_div, + orthogonal_rotation ? data->taps.h_taps_c : data->taps.v_taps_c, + orthogonal_rotation ? data->ratios.horz_c : data->ratios.vert_c, + orthogonal_rotation ? &data->inits.h_c : &data->inits.v_c, + &data->viewport_c.y, + &data->viewport_c.height); /* Interlaced inits based on final vert inits */ data->inits.v_bot = dc_fixpt_add(data->inits.v, data->ratios.vert); data->inits.v_c_bot = dc_fixpt_add(data->inits.v_c, data->ratios.vert_c); - if (pipe_ctx->plane_state->rotation == ROTATION_ANGLE_90 || - pipe_ctx->plane_state->rotation == ROTATION_ANGLE_270) { - rect_swap_helper(&data->viewport_c); - rect_swap_helper(&data->viewport); - } } bool resource_build_scaling_params(struct pipe_ctx *pipe_ctx) { const struct dc_plane_state *plane_state = pipe_ctx->plane_state; struct dc_crtc_timing *timing = &pipe_ctx->stream->timing; - struct rect recout_full = { 0 }; bool res = false; DC_LOGGER_INIT(pipe_ctx->stream->ctx->logger); /* Important: scaling ratio calculation requires pixel format, @@ -1105,7 +931,7 @@ bool resource_build_scaling_params(struct pipe_ctx *pipe_ctx) if (pipe_ctx->plane_res.scl_data.viewport.height < 16 || pipe_ctx->plane_res.scl_data.viewport.width < 16) return false; - calculate_recout(pipe_ctx, &recout_full); + calculate_recout(pipe_ctx); /** * Setting line buffer pixel depth to 24bpp yields banding @@ -1146,7 +972,7 @@ bool resource_build_scaling_params(struct pipe_ctx *pipe_ctx) if (res) /* May need to re-check lb size after this in some obscure scenario */ - calculate_inits_and_adj_vp(pipe_ctx, &recout_full); + calculate_inits_and_adj_vp(pipe_ctx); DC_LOG_SCALER( "%s: Viewport:\nheight:%d width:%d x:%d " -- cgit v1.2.3 From a7513419610b118eeabda6e85de187030fea57ae Mon Sep 17 00:00:00 2001 From: Steven Chiu Date: Fri, 19 Oct 2018 15:04:45 -0400 Subject: drm/amd/display: 3.2.06 Signed-off-by: Steven Chiu Reviewed-by: Tony Cheng Acked-by: Bhawanpreet Lakha Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/display/dc/dc.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/gpu/drm') diff --git a/drivers/gpu/drm/amd/display/dc/dc.h b/drivers/gpu/drm/amd/display/dc/dc.h index f4bfead398a4..18865a76ea55 100644 --- a/drivers/gpu/drm/amd/display/dc/dc.h +++ b/drivers/gpu/drm/amd/display/dc/dc.h @@ -38,7 +38,7 @@ #include "inc/compressor.h" #include "dml/display_mode_lib.h" -#define DC_VER "3.2.05" +#define DC_VER "3.2.06" #define MAX_SURFACES 3 #define MAX_STREAMS 6 -- cgit v1.2.3 From 818832bf2bc0d86d2a114d3baadfae12a40f7f36 Mon Sep 17 00:00:00 2001 From: Xiaodong Yan Date: Wed, 24 Oct 2018 02:08:53 +0800 Subject: drm/amd/display: retry 3 times before successfully reading DPCD Extended Receiver Capability Field [Why] 1.dpcd extended receiver capability sometimes read fail, and corrupted data leads to sink caps is not correct. 2.sometimes sink reply ack with fewer data [How] check the return value of core_link_read_dpcd, try to read again when failure happens Signed-off-by: Xiaodong Yan Reviewed-by: Wenjing Liu Acked-by: Bhawanpreet Lakha Acked-by: Tony Cheng Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/display/dc/core/dc_link_dp.c | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) (limited to 'drivers/gpu/drm') diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_link_dp.c b/drivers/gpu/drm/amd/display/dc/core/dc_link_dp.c index d91df5ef0cb3..4d1f8ac069c1 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc_link_dp.c +++ b/drivers/gpu/drm/amd/display/dc/core/dc_link_dp.c @@ -2371,11 +2371,22 @@ static bool retrieve_link_cap(struct dc_link *link) dpcd_data[DP_TRAINING_AUX_RD_INTERVAL]; if (aux_rd_interval.bits.EXT_RECIEVER_CAP_FIELD_PRESENT == 1) { - core_link_read_dpcd( + uint8_t ext_cap_data[16]; + + memset(ext_cap_data, '\0', sizeof(ext_cap_data)); + for (i = 0; i < read_dpcd_retry_cnt; i++) { + status = core_link_read_dpcd( link, DP_DP13_DPCD_REV, - dpcd_data, - sizeof(dpcd_data)); + ext_cap_data, + sizeof(ext_cap_data)); + if (status == DC_OK) { + memcpy(dpcd_data, ext_cap_data, sizeof(dpcd_data)); + break; + } + } + if (status != DC_OK) + dm_error("%s: Read extend caps data failed, use cap from dpcd 0.\n", __func__); } } -- cgit v1.2.3 From 00737c59a231a4eab955f6cd53c88e7c6449abd0 Mon Sep 17 00:00:00 2001 From: Eric Bernstein Date: Mon, 29 Oct 2018 16:05:47 -0400 Subject: drm/amd/display: get tail pipe before aquire free pipe [Why] For some complicated blending transition cases, the head pipe of the second stream may end up being a higher pipe index than the free pipe. In those cases dc_add_plane_to_context will incorrectly set the tail_pipe to the free pipe, which will cause the top_pipe and bottom_pipe to be the same [How] Move the call to resource_get_tail_pipe_for_stream() to be before call to acquire_free_pipe_for_stream(). Signed-off-by: Eric Bernstein Reviewed-by: Dmytro Laktyushkin Acked-by: Bhawanpreet Lakha Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/display/dc/core/dc_resource.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) (limited to 'drivers/gpu/drm') diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_resource.c b/drivers/gpu/drm/amd/display/dc/core/dc_resource.c index 0a1985ca9882..0bb844a7b990 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc_resource.c +++ b/drivers/gpu/drm/amd/display/dc/core/dc_resource.c @@ -1182,6 +1182,9 @@ bool dc_add_plane_to_context( return false; } + tail_pipe = resource_get_tail_pipe_for_stream(&context->res_ctx, stream); + ASSERT(tail_pipe); + free_pipe = acquire_free_pipe_for_stream(context, pool, stream); #if defined(CONFIG_DRM_AMD_DC_DCN1_0) @@ -1199,10 +1202,6 @@ bool dc_add_plane_to_context( free_pipe->plane_state = plane_state; if (head_pipe != free_pipe) { - - tail_pipe = resource_get_tail_pipe_for_stream(&context->res_ctx, stream); - ASSERT(tail_pipe); - free_pipe->stream_res.tg = tail_pipe->stream_res.tg; free_pipe->stream_res.abm = tail_pipe->stream_res.abm; free_pipe->stream_res.opp = tail_pipe->stream_res.opp; -- cgit v1.2.3 From 14fee4ca84ecaa42aeada8ff404269e8c0a15efb Mon Sep 17 00:00:00 2001 From: Joshua Aberback Date: Tue, 30 Oct 2018 15:34:33 -0400 Subject: drm/amd/display: Adjust stream enable sequence [Why] We observed an issue where a display would not accept programming of the ignore_MSA_timing_param bit if the stream was blanked. [How] move enable_stream_features from enable_link_dp to core_link_enable_stream, after unblank_stream Signed-off-by: Joshua Aberback Reviewed-by: Jun Lei Acked-by: Anthony Koo Acked-by: Bhawanpreet Lakha Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/display/dc/core/dc_link.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'drivers/gpu/drm') diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_link.c b/drivers/gpu/drm/amd/display/dc/core/dc_link.c index fe557e7142a1..abcfc05e06e8 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc_link.c +++ b/drivers/gpu/drm/amd/display/dc/core/dc_link.c @@ -1396,8 +1396,6 @@ static enum dc_status enable_link_dp( else status = DC_FAIL_DP_LINK_TRAINING; - enable_stream_features(pipe_ctx); - return status; } @@ -2594,6 +2592,9 @@ void core_link_enable_stream( core_dc->hwss.unblank_stream(pipe_ctx, &pipe_ctx->stream->sink->link->cur_link_settings); + if (dc_is_dp_signal(pipe_ctx->stream->signal)) + enable_stream_features(pipe_ctx); + dc_link_set_backlight_level(pipe_ctx->stream->sink->link, pipe_ctx->stream->bl_pwm_level, 0, -- cgit v1.2.3 From 1a1adf172f6a9747d5dd2d9236af28ccff8646a8 Mon Sep 17 00:00:00 2001 From: Dmytro Laktyushkin Date: Wed, 31 Oct 2018 07:59:54 -0400 Subject: drm/amd/display: fix pipe interdependent hubp programming A number of registers need to be updated for all active pipes wherever any pipe causes a change in watermarks. This change separates programming of these registers into a separate function call that is called for all active pipes during a bw update. Signed-off-by: Dmytro Laktyushkin Reviewed-by: Tony Cheng Acked-by: Bhawanpreet Lakha Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hubp.c | 87 +++++++++++----------- .../drm/amd/display/dc/dcn10/dcn10_hw_sequencer.c | 30 ++++++++ drivers/gpu/drm/amd/display/dc/inc/hw/hubp.h | 5 ++ 3 files changed, 78 insertions(+), 44 deletions(-) (limited to 'drivers/gpu/drm') diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hubp.c b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hubp.c index 6127fd30899b..345af015d061 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hubp.c +++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hubp.c @@ -573,19 +573,6 @@ void hubp1_program_deadline( REFCYC_X_AFTER_SCALER, dlg_attr->refcyc_x_after_scaler, DST_Y_AFTER_SCALER, dlg_attr->dst_y_after_scaler); - if (REG(PREFETCH_SETTINS)) - REG_SET_2(PREFETCH_SETTINS, 0, - DST_Y_PREFETCH, dlg_attr->dst_y_prefetch, - VRATIO_PREFETCH, dlg_attr->vratio_prefetch); - else - REG_SET_2(PREFETCH_SETTINGS, 0, - DST_Y_PREFETCH, dlg_attr->dst_y_prefetch, - VRATIO_PREFETCH, dlg_attr->vratio_prefetch); - - REG_SET_2(VBLANK_PARAMETERS_0, 0, - DST_Y_PER_VM_VBLANK, dlg_attr->dst_y_per_vm_vblank, - DST_Y_PER_ROW_VBLANK, dlg_attr->dst_y_per_row_vblank); - REG_SET(REF_FREQ_TO_PIX_FREQ, 0, REF_FREQ_TO_PIX_FREQ, dlg_attr->ref_freq_to_pix_freq); @@ -593,9 +580,6 @@ void hubp1_program_deadline( REG_SET(VBLANK_PARAMETERS_1, 0, REFCYC_PER_PTE_GROUP_VBLANK_L, dlg_attr->refcyc_per_pte_group_vblank_l); - REG_SET(VBLANK_PARAMETERS_3, 0, - REFCYC_PER_META_CHUNK_VBLANK_L, dlg_attr->refcyc_per_meta_chunk_vblank_l); - if (REG(NOM_PARAMETERS_0)) REG_SET(NOM_PARAMETERS_0, 0, DST_Y_PER_PTE_ROW_NOM_L, dlg_attr->dst_y_per_pte_row_nom_l); @@ -610,27 +594,13 @@ void hubp1_program_deadline( REG_SET(NOM_PARAMETERS_5, 0, REFCYC_PER_META_CHUNK_NOM_L, dlg_attr->refcyc_per_meta_chunk_nom_l); - REG_SET_2(PER_LINE_DELIVERY_PRE, 0, - REFCYC_PER_LINE_DELIVERY_PRE_L, dlg_attr->refcyc_per_line_delivery_pre_l, - REFCYC_PER_LINE_DELIVERY_PRE_C, dlg_attr->refcyc_per_line_delivery_pre_c); - REG_SET_2(PER_LINE_DELIVERY, 0, REFCYC_PER_LINE_DELIVERY_L, dlg_attr->refcyc_per_line_delivery_l, REFCYC_PER_LINE_DELIVERY_C, dlg_attr->refcyc_per_line_delivery_c); - if (REG(PREFETCH_SETTINS_C)) - REG_SET(PREFETCH_SETTINS_C, 0, - VRATIO_PREFETCH_C, dlg_attr->vratio_prefetch_c); - else - REG_SET(PREFETCH_SETTINGS_C, 0, - VRATIO_PREFETCH_C, dlg_attr->vratio_prefetch_c); - REG_SET(VBLANK_PARAMETERS_2, 0, REFCYC_PER_PTE_GROUP_VBLANK_C, dlg_attr->refcyc_per_pte_group_vblank_c); - REG_SET(VBLANK_PARAMETERS_4, 0, - REFCYC_PER_META_CHUNK_VBLANK_C, dlg_attr->refcyc_per_meta_chunk_vblank_c); - if (REG(NOM_PARAMETERS_2)) REG_SET(NOM_PARAMETERS_2, 0, DST_Y_PER_PTE_ROW_NOM_C, dlg_attr->dst_y_per_pte_row_nom_c); @@ -650,10 +620,6 @@ void hubp1_program_deadline( QoS_LEVEL_LOW_WM, ttu_attr->qos_level_low_wm, QoS_LEVEL_HIGH_WM, ttu_attr->qos_level_high_wm); - REG_SET_2(DCN_GLOBAL_TTU_CNTL, 0, - MIN_TTU_VBLANK, ttu_attr->min_ttu_vblank, - QoS_LEVEL_FLIP, ttu_attr->qos_level_flip); - /* TTU - per luma/chroma */ /* Assumed surf0 is luma and 1 is chroma */ @@ -662,25 +628,15 @@ void hubp1_program_deadline( QoS_LEVEL_FIXED, ttu_attr->qos_level_fixed_l, QoS_RAMP_DISABLE, ttu_attr->qos_ramp_disable_l); - REG_SET(DCN_SURF0_TTU_CNTL1, 0, - REFCYC_PER_REQ_DELIVERY_PRE, - ttu_attr->refcyc_per_req_delivery_pre_l); - REG_SET_3(DCN_SURF1_TTU_CNTL0, 0, REFCYC_PER_REQ_DELIVERY, ttu_attr->refcyc_per_req_delivery_c, QoS_LEVEL_FIXED, ttu_attr->qos_level_fixed_c, QoS_RAMP_DISABLE, ttu_attr->qos_ramp_disable_c); - REG_SET(DCN_SURF1_TTU_CNTL1, 0, - REFCYC_PER_REQ_DELIVERY_PRE, - ttu_attr->refcyc_per_req_delivery_pre_c); - REG_SET_3(DCN_CUR0_TTU_CNTL0, 0, REFCYC_PER_REQ_DELIVERY, ttu_attr->refcyc_per_req_delivery_cur0, QoS_LEVEL_FIXED, ttu_attr->qos_level_fixed_cur0, QoS_RAMP_DISABLE, ttu_attr->qos_ramp_disable_cur0); - REG_SET(DCN_CUR0_TTU_CNTL1, 0, - REFCYC_PER_REQ_DELIVERY_PRE, ttu_attr->refcyc_per_req_delivery_pre_cur0); } static void hubp1_setup( @@ -698,6 +654,48 @@ static void hubp1_setup( hubp1_vready_workaround(hubp, pipe_dest); } +static void hubp1_setup_interdependent( + struct hubp *hubp, + struct _vcs_dpi_display_dlg_regs_st *dlg_attr, + struct _vcs_dpi_display_ttu_regs_st *ttu_attr) +{ + struct dcn10_hubp *hubp1 = TO_DCN10_HUBP(hubp); + + REG_SET_2(PREFETCH_SETTINS, 0, + DST_Y_PREFETCH, dlg_attr->dst_y_prefetch, + VRATIO_PREFETCH, dlg_attr->vratio_prefetch); + + REG_SET(PREFETCH_SETTINS_C, 0, + VRATIO_PREFETCH_C, dlg_attr->vratio_prefetch_c); + + REG_SET_2(VBLANK_PARAMETERS_0, 0, + DST_Y_PER_VM_VBLANK, dlg_attr->dst_y_per_vm_vblank, + DST_Y_PER_ROW_VBLANK, dlg_attr->dst_y_per_row_vblank); + + REG_SET(VBLANK_PARAMETERS_3, 0, + REFCYC_PER_META_CHUNK_VBLANK_L, dlg_attr->refcyc_per_meta_chunk_vblank_l); + + REG_SET(VBLANK_PARAMETERS_4, 0, + REFCYC_PER_META_CHUNK_VBLANK_C, dlg_attr->refcyc_per_meta_chunk_vblank_c); + + REG_SET_2(PER_LINE_DELIVERY_PRE, 0, + REFCYC_PER_LINE_DELIVERY_PRE_L, dlg_attr->refcyc_per_line_delivery_pre_l, + REFCYC_PER_LINE_DELIVERY_PRE_C, dlg_attr->refcyc_per_line_delivery_pre_c); + + REG_SET(DCN_SURF0_TTU_CNTL1, 0, + REFCYC_PER_REQ_DELIVERY_PRE, + ttu_attr->refcyc_per_req_delivery_pre_l); + REG_SET(DCN_SURF1_TTU_CNTL1, 0, + REFCYC_PER_REQ_DELIVERY_PRE, + ttu_attr->refcyc_per_req_delivery_pre_c); + REG_SET(DCN_CUR0_TTU_CNTL1, 0, + REFCYC_PER_REQ_DELIVERY_PRE, ttu_attr->refcyc_per_req_delivery_pre_cur0); + + REG_SET_2(DCN_GLOBAL_TTU_CNTL, 0, + MIN_TTU_VBLANK, ttu_attr->min_ttu_vblank, + QoS_LEVEL_FLIP, ttu_attr->qos_level_flip); +} + bool hubp1_is_flip_pending(struct hubp *hubp) { uint32_t flip_pending = 0; @@ -1186,6 +1184,7 @@ static const struct hubp_funcs dcn10_hubp_funcs = { hubp1_program_surface_config, .hubp_is_flip_pending = hubp1_is_flip_pending, .hubp_setup = hubp1_setup, + .hubp_setup_interdependent = hubp1_setup_interdependent, .hubp_set_vm_system_aperture_settings = hubp1_set_vm_system_aperture_settings, .hubp_set_vm_context0_settings = hubp1_set_vm_context0_settings, .set_blank = hubp1_set_blank, diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer.c b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer.c index 84cfe709bdc2..0dde7922ccba 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer.c +++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer.c @@ -2068,6 +2068,10 @@ void update_dchubp_dpp( &pipe_ctx->ttu_regs, &pipe_ctx->rq_regs, &pipe_ctx->pipe_dlg_param); + hubp->funcs->hubp_setup_interdependent( + hubp, + &pipe_ctx->dlg_regs, + &pipe_ctx->ttu_regs); } size.grph.surface_size = pipe_ctx->plane_res.scl_data.viewport; @@ -2338,6 +2342,32 @@ static void dcn10_apply_ctx_for_surface( dcn10_pipe_control_lock(dc, top_pipe_to_program, false); + if (top_pipe_to_program->plane_state && + top_pipe_to_program->plane_state->update_flags.bits.full_update) + for (i = 0; i < dc->res_pool->pipe_count; i++) { + struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i]; + + /* Skip inactive pipes and ones already updated */ + if (!pipe_ctx->stream || pipe_ctx->stream == stream) + continue; + + pipe_ctx->stream_res.tg->funcs->lock(pipe_ctx->stream_res.tg); + + pipe_ctx->plane_res.hubp->funcs->hubp_setup_interdependent( + pipe_ctx->plane_res.hubp, + &pipe_ctx->dlg_regs, + &pipe_ctx->ttu_regs); + } + + for (i = 0; i < dc->res_pool->pipe_count; i++) { + struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i]; + + if (!pipe_ctx->stream || pipe_ctx->stream == stream) + continue; + + dcn10_pipe_control_lock(dc, pipe_ctx, false); + } + if (num_planes == 0) false_optc_underflow_wa(dc, stream, tg); diff --git a/drivers/gpu/drm/amd/display/dc/inc/hw/hubp.h b/drivers/gpu/drm/amd/display/dc/inc/hw/hubp.h index 8f4f40646b4d..04c6989aac58 100644 --- a/drivers/gpu/drm/amd/display/dc/inc/hw/hubp.h +++ b/drivers/gpu/drm/amd/display/dc/inc/hw/hubp.h @@ -63,6 +63,11 @@ struct hubp_funcs { struct _vcs_dpi_display_rq_regs_st *rq_regs, struct _vcs_dpi_display_pipe_dest_params_st *pipe_dest); + void (*hubp_setup_interdependent)( + struct hubp *hubp, + struct _vcs_dpi_display_dlg_regs_st *dlg_regs, + struct _vcs_dpi_display_ttu_regs_st *ttu_regs); + void (*dcc_control)(struct hubp *hubp, bool enable, bool independent_64b_blks); void (*mem_program_viewport)( -- cgit v1.2.3 From d9672a5bfbb506d3276403a309c5013b4fd7c56c Mon Sep 17 00:00:00 2001 From: Charlene Liu Date: Wed, 31 Oct 2018 16:51:40 -0400 Subject: drm/amd/display: expose surface confirm color function expose dcn10_get_surface_visual_confirm_color() to be used in the future Signed-off-by: Charlene Liu Reviewed-by: Dmytro Laktyushkin Acked-by: Bhawanpreet Lakha Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer.c | 4 ++-- drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer.h | 8 ++++++++ 2 files changed, 10 insertions(+), 2 deletions(-) (limited to 'drivers/gpu/drm') diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer.c b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer.c index 0dde7922ccba..0bd33a713836 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer.c +++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer.c @@ -1771,7 +1771,7 @@ bool is_rgb_cspace(enum dc_color_space output_color_space) } } -static void dcn10_get_surface_visual_confirm_color( +void dcn10_get_surface_visual_confirm_color( const struct pipe_ctx *pipe_ctx, struct tg_color *color) { @@ -1807,7 +1807,7 @@ static void dcn10_get_surface_visual_confirm_color( } } -static void dcn10_get_hdr_visual_confirm_color( +void dcn10_get_hdr_visual_confirm_color( struct pipe_ctx *pipe_ctx, struct tg_color *color) { diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer.h b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer.h index 91bb77b468dd..f8eea10e4c64 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer.h +++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer.h @@ -63,6 +63,14 @@ void dcn10_program_pte_vm(struct dce_hwseq *hws, struct hubp *hubp); void set_hdr_multiplier(struct pipe_ctx *pipe_ctx); +void dcn10_get_surface_visual_confirm_color( + const struct pipe_ctx *pipe_ctx, + struct tg_color *color); + +void dcn10_get_hdr_visual_confirm_color( + struct pipe_ctx *pipe_ctx, + struct tg_color *color); + void update_dchubp_dpp( struct dc *dc, struct pipe_ctx *pipe_ctx, -- cgit v1.2.3 From 6ccda157732d7ff6773a325f3d3252ad4d56f015 Mon Sep 17 00:00:00 2001 From: David Francis Date: Thu, 25 Oct 2018 15:47:43 -0400 Subject: drm/amd/display: Get backlight controller id from link [Why] dc_link_set_backlight_level can be called from a context where the stream is unknown. In this case, we can still find which controller is driving this particular backlight [How] Compare links for equality instead of streams Signed-off-by: David Francis Reviewed-by: Nicholas Kazlauskas Acked-by: Bhawanpreet Lakha Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/display/dc/core/dc_link.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers/gpu/drm') diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_link.c b/drivers/gpu/drm/amd/display/dc/core/dc_link.c index abcfc05e06e8..948596a02392 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc_link.c +++ b/drivers/gpu/drm/amd/display/dc/core/dc_link.c @@ -2173,11 +2173,11 @@ bool dc_link_set_backlight_level(const struct dc_link *link, backlight_pwm_u16_16, backlight_pwm_u16_16); if (dc_is_embedded_signal(link->connector_signal)) { - if (stream != NULL) { - for (i = 0; i < MAX_PIPES; i++) { + for (i = 0; i < MAX_PIPES; i++) { + if (core_dc->current_state->res_ctx.pipe_ctx[i].stream) { if (core_dc->current_state->res_ctx. - pipe_ctx[i].stream - == stream) + pipe_ctx[i].stream->sink->link + == link) /* DMCU -1 for all controller id values, * therefore +1 here */ -- cgit v1.2.3 From bed1ed366d5f68a9e038364ec22fe34ed361c1ba Mon Sep 17 00:00:00 2001 From: Emily Deng Date: Wed, 14 Nov 2018 23:20:13 +0800 Subject: drm/amd/amdgpu/sriov: Aligned the definition with libgv Aligned the amd_sriov_msg_pf2vf_info_header and amd_sriov_msg_pf2vf_info_header's definition with libgv. Signed-off-by: Emily Deng Reviewed-by: Frank.Min Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/amdgpu_virt.c | 2 +- drivers/gpu/drm/amd/amdgpu/amdgpu_virt.h | 24 ++++++++++++++---------- 2 files changed, 15 insertions(+), 11 deletions(-) (limited to 'drivers/gpu/drm') diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_virt.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_virt.c index cfee74732edb..462a04e0f5e6 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_virt.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_virt.c @@ -334,7 +334,7 @@ void amdgpu_virt_init_data_exchange(struct amdgpu_device *adev) if (adev->fw_vram_usage.va != NULL) { adev->virt.fw_reserve.p_pf2vf = - (struct amdgim_pf2vf_info_header *)( + (struct amd_sriov_msg_pf2vf_info_header *)( adev->fw_vram_usage.va + AMDGIM_DATAEXCHANGE_OFFSET); AMDGPU_FW_VRAM_PF2VF_READ(adev, header.size, &pf2vf_size); AMDGPU_FW_VRAM_PF2VF_READ(adev, checksum, &checksum); diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_virt.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_virt.h index 0728fbc9a692..722deefc0a7e 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_virt.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_virt.h @@ -63,8 +63,8 @@ struct amdgpu_virt_ops { * Firmware Reserve Frame buffer */ struct amdgpu_virt_fw_reserve { - struct amdgim_pf2vf_info_header *p_pf2vf; - struct amdgim_vf2pf_info_header *p_vf2pf; + struct amd_sriov_msg_pf2vf_info_header *p_pf2vf; + struct amd_sriov_msg_vf2pf_info_header *p_vf2pf; unsigned int checksum_key; }; /* @@ -85,15 +85,17 @@ enum AMDGIM_FEATURE_FLAG { AMDGIM_FEATURE_GIM_FLR_VRAMLOST = 0x4, }; -struct amdgim_pf2vf_info_header { +struct amd_sriov_msg_pf2vf_info_header { /* the total structure size in byte. */ uint32_t size; /* version of this structure, written by the GIM */ uint32_t version; + /* reserved */ + uint32_t reserved[2]; } __aligned(4); struct amdgim_pf2vf_info_v1 { /* header contains size and version */ - struct amdgim_pf2vf_info_header header; + struct amd_sriov_msg_pf2vf_info_header header; /* max_width * max_height */ unsigned int uvd_enc_max_pixels_count; /* 16x16 pixels/sec, codec independent */ @@ -112,7 +114,7 @@ struct amdgim_pf2vf_info_v1 { struct amdgim_pf2vf_info_v2 { /* header contains size and version */ - struct amdgim_pf2vf_info_header header; + struct amd_sriov_msg_pf2vf_info_header header; /* use private key from mailbox 2 to create chueksum */ uint32_t checksum; /* The features flags of the GIM driver supports. */ @@ -137,20 +139,22 @@ struct amdgim_pf2vf_info_v2 { uint64_t vcefw_kboffset; /* VCE FW size in KB */ uint32_t vcefw_ksize; - uint32_t reserved[AMDGIM_GET_STRUCTURE_RESERVED_SIZE(256, 0, 0, (9 + sizeof(struct amdgim_pf2vf_info_header)/sizeof(uint32_t)), 3)]; + uint32_t reserved[AMDGIM_GET_STRUCTURE_RESERVED_SIZE(256, 0, 0, (9 + sizeof(struct amd_sriov_msg_pf2vf_info_header)/sizeof(uint32_t)), 3)]; } __aligned(4); -struct amdgim_vf2pf_info_header { +struct amd_sriov_msg_vf2pf_info_header { /* the total structure size in byte. */ uint32_t size; /*version of this structure, written by the guest */ uint32_t version; + /* reserved */ + uint32_t reserved[2]; } __aligned(4); struct amdgim_vf2pf_info_v1 { /* header contains size and version */ - struct amdgim_vf2pf_info_header header; + struct amd_sriov_msg_vf2pf_info_header header; /* driver version */ char driver_version[64]; /* driver certification, 1=WHQL, 0=None */ @@ -180,7 +184,7 @@ struct amdgim_vf2pf_info_v1 { struct amdgim_vf2pf_info_v2 { /* header contains size and version */ - struct amdgim_vf2pf_info_header header; + struct amd_sriov_msg_vf2pf_info_header header; uint32_t checksum; /* driver version */ uint8_t driver_version[64]; @@ -206,7 +210,7 @@ struct amdgim_vf2pf_info_v2 { uint32_t uvd_enc_usage; /* guest uvd engine usage percentage. 0xffff means N/A. */ uint32_t uvd_enc_health; - uint32_t reserved[AMDGIM_GET_STRUCTURE_RESERVED_SIZE(256, 64, 0, (12 + sizeof(struct amdgim_vf2pf_info_header)/sizeof(uint32_t)), 0)]; + uint32_t reserved[AMDGIM_GET_STRUCTURE_RESERVED_SIZE(256, 64, 0, (12 + sizeof(struct amd_sriov_msg_vf2pf_info_header)/sizeof(uint32_t)), 0)]; } __aligned(4); #define AMDGPU_FW_VRAM_VF2PF_VER 2 -- cgit v1.2.3 From 900cc36338188773230c3c7fa099619bf532517b Mon Sep 17 00:00:00 2001 From: YueHaibing Date: Thu, 15 Nov 2018 20:00:35 +0800 Subject: drm/amdgpu: remove set but not used variable 'ring' MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixes gcc '-Wunused-but-set-variable' warning: drivers/gpu/drm/amd/amdgpu/psp_v10_0.c: In function 'psp_v10_0_ring_stop': drivers/gpu/drm/amd/amdgpu/psp_v10_0.c:230:19: warning: variable 'ring' set but not used [-Wunused-but-set-variable] drivers/gpu/drm/amd/amdgpu/psp_v3_1.c: In function 'psp_v3_1_ring_stop': drivers/gpu/drm/amd/amdgpu/psp_v3_1.c:359:19: warning: variable ‘ring’ set but not used [-Wunused-but-set-variable] It not used since commit 4ef72453311a ("drm/amdgpu: added api for stopping psp ring (v2)") Signed-off-by: YueHaibing Reviewed-by: Huang Rui Acked-by: Christian König Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/psp_v10_0.c | 3 --- drivers/gpu/drm/amd/amdgpu/psp_v3_1.c | 3 --- 2 files changed, 6 deletions(-) (limited to 'drivers/gpu/drm') diff --git a/drivers/gpu/drm/amd/amdgpu/psp_v10_0.c b/drivers/gpu/drm/amd/amdgpu/psp_v10_0.c index 295c2205485a..d78b4306a36f 100644 --- a/drivers/gpu/drm/amd/amdgpu/psp_v10_0.c +++ b/drivers/gpu/drm/amd/amdgpu/psp_v10_0.c @@ -240,12 +240,9 @@ static int psp_v10_0_ring_stop(struct psp_context *psp, enum psp_ring_type ring_type) { int ret = 0; - struct psp_ring *ring; unsigned int psp_ring_reg = 0; struct amdgpu_device *adev = psp->adev; - ring = &psp->km_ring; - /* Write the ring destroy command to C2PMSG_64 */ psp_ring_reg = 3 << 16; WREG32_SOC15(MP0, 0, mmMP0_SMN_C2PMSG_64, psp_ring_reg); diff --git a/drivers/gpu/drm/amd/amdgpu/psp_v3_1.c b/drivers/gpu/drm/amd/amdgpu/psp_v3_1.c index 9cea0bbe4525..64c267f37d4b 100644 --- a/drivers/gpu/drm/amd/amdgpu/psp_v3_1.c +++ b/drivers/gpu/drm/amd/amdgpu/psp_v3_1.c @@ -356,12 +356,9 @@ static int psp_v3_1_ring_stop(struct psp_context *psp, enum psp_ring_type ring_type) { int ret = 0; - struct psp_ring *ring; unsigned int psp_ring_reg = 0; struct amdgpu_device *adev = psp->adev; - ring = &psp->km_ring; - /* Write the ring destroy command to C2PMSG_64 */ psp_ring_reg = 3 << 16; WREG32_SOC15(MP0, 0, mmMP0_SMN_C2PMSG_64, psp_ring_reg); -- cgit v1.2.3 From e2306cc6a07aefc458982b3d7ae1e146515ed656 Mon Sep 17 00:00:00 2001 From: Nicholas Kazlauskas Date: Thu, 15 Nov 2018 17:19:12 -0500 Subject: drm/amdgpu: Add amdgpu "max bpc" connector property (v2) [Why] Many panels support more than 8bpc but some modes are unavailable while running at greater than 8bpc due to DP/HDMI bandwidth constraints. Support for more than 8bpc was added recently in the driver but it defaults to the maximum supported bpc - locking out these modes. This should be a user configurable option such that the user can select what bpc configuration they would like. [How] This patch introduces the "max bpc" amdgpu driver specific connector property so the user can limit the maximum bpc. It ranges from 8 to 16. This doesn't directly set the preferred bpc for the panel since it follows Intel's existing driver conventions. This proprety should be removed once common drm support for max bpc lands. v2: rebase on upstream (Alex) Signed-off-by: Nicholas Kazlauskas Acked-by: Alex Deucher Reviewed-by: Harry Wentland Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/amdgpu_display.c | 7 +++++++ drivers/gpu/drm/amd/amdgpu/amdgpu_mode.h | 2 ++ 2 files changed, 9 insertions(+) (limited to 'drivers/gpu/drm') diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_display.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_display.c index 6748cd7fc129..686a26de50f9 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_display.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_display.c @@ -626,6 +626,13 @@ int amdgpu_display_modeset_create_props(struct amdgpu_device *adev) "dither", amdgpu_dither_enum_list, sz); + if (amdgpu_device_has_dc_support(adev)) { + adev->mode_info.max_bpc_property = + drm_property_create_range(adev->ddev, 0, "max bpc", 8, 16); + if (!adev->mode_info.max_bpc_property) + return -ENOMEM; + } + return 0; } diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_mode.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_mode.h index 11723d8fffbd..0dc2c5c57015 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_mode.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_mode.h @@ -338,6 +338,8 @@ struct amdgpu_mode_info { struct drm_property *audio_property; /* FMT dithering */ struct drm_property *dither_property; + /* maximum number of bits per channel for monitor color */ + struct drm_property *max_bpc_property; /* hardcoded DFP edid from BIOS */ struct edid *bios_hardcoded_edid; int bios_hardcoded_edid_size; -- cgit v1.2.3 From cedde71cc61bdf5e2f386f06bada29fe9fe11b78 Mon Sep 17 00:00:00 2001 From: Nicholas Kazlauskas Date: Thu, 15 Nov 2018 17:21:34 -0500 Subject: drm/amd/display: Support amdgpu "max bpc" connector property (v2) [Why] Many panels support more than 8bpc but some modes are unavailable while running at greater than 8bpc due to DP/HDMI bandwidth constraints. Support for more than 8bpc was added recently in the driver but it defaults to the maximum supported bpc - locking out these modes. This should be a user configurable option such that the user can select what bpc configuration they would like. [How] This patch adds support for getting and setting the amdgpu driver specific "max bpc" property on the connector. It also adds support for limiting the output bpc based on the property value. The default limitation is the lowest value in the range, 8bpc. This was the old value before the range was uncapped. This patch should be updated/replaced later once common drm support for max bpc lands. Bugzilla: https://bugs.freedesktop.org/108542 Bugzilla: https://bugzilla.kernel.org/show_bug.cgi?id=201585 Bugzilla: https://bugzilla.kernel.org/show_bug.cgi?id=200645 Fixes: e03fd3f300f6 ("drm/amd/display: Do not limit color depth to 8bpc") v2: rebase on upstream (Alex) Signed-off-by: Nicholas Kazlauskas Acked-by: Alex Deucher Reviewed-by: Harry Wentland Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 16 ++++++++++++++++ drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h | 1 + 2 files changed, 17 insertions(+) (limited to 'drivers/gpu/drm') diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c index aa43bb253ea2..d8d0b206a79c 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c @@ -2422,8 +2422,15 @@ static void update_stream_scaling_settings(const struct drm_display_mode *mode, static enum dc_color_depth convert_color_depth_from_display_info(const struct drm_connector *connector) { + struct dm_connector_state *dm_conn_state = + to_dm_connector_state(connector->state); uint32_t bpc = connector->display_info.bpc; + /* TODO: Remove this when there's support for max_bpc in drm */ + if (dm_conn_state && bpc > dm_conn_state->max_bpc) + /* Round down to nearest even number. */ + bpc = dm_conn_state->max_bpc - (dm_conn_state->max_bpc & 1); + switch (bpc) { case 0: /* @@ -3007,6 +3014,9 @@ int amdgpu_dm_connector_atomic_set_property(struct drm_connector *connector, } else if (property == adev->mode_info.underscan_property) { dm_new_state->underscan_enable = val; ret = 0; + } else if (property == adev->mode_info.max_bpc_property) { + dm_new_state->max_bpc = val; + ret = 0; } return ret; @@ -3049,6 +3059,9 @@ int amdgpu_dm_connector_atomic_get_property(struct drm_connector *connector, } else if (property == adev->mode_info.underscan_property) { *val = dm_state->underscan_enable; ret = 0; + } else if (property == adev->mode_info.max_bpc_property) { + *val = dm_state->max_bpc; + ret = 0; } return ret; } @@ -3859,6 +3872,9 @@ void amdgpu_dm_connector_init_helper(struct amdgpu_display_manager *dm, drm_object_attach_property(&aconnector->base.base, adev->mode_info.underscan_vborder_property, 0); + drm_object_attach_property(&aconnector->base.base, + adev->mode_info.max_bpc_property, + 0); } diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h index d6960644d714..607c3cdd7d0c 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h @@ -252,6 +252,7 @@ struct dm_connector_state { enum amdgpu_rmx_type scaling; uint8_t underscan_vborder; uint8_t underscan_hborder; + uint8_t max_bpc; bool underscan_enable; bool freesync_enable; bool freesync_capable; -- cgit v1.2.3 From d7203171177aa8063e8a80cbc7988386e5c0ceda Mon Sep 17 00:00:00 2001 From: David Francis Date: Thu, 25 Oct 2018 14:18:12 -0400 Subject: drm/amd/display: Clean up DCN1 clock requests [Why] There was a full clock request struct of which only one value was being used. [How] Replace the struct with a uint32_t Signed-off-by: David Francis Reviewed-by: Nicholas Kazlauskas Reviewed-by: Sun peng Li Acked-by: Bhawanpreet Lakha Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/display/dc/dcn10/dcn10_clk_mgr.c | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) (limited to 'drivers/gpu/drm') diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_clk_mgr.c b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_clk_mgr.c index 20f531d27e2b..f9d7d2c26cc2 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_clk_mgr.c +++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_clk_mgr.c @@ -223,7 +223,7 @@ static void dcn1_update_clocks(struct clk_mgr *clk_mgr, &dc->res_pool->pp_smu_req; struct pp_smu_display_requirement_rv smu_req = *smu_req_cur; struct pp_smu_funcs_rv *pp_smu = dc->res_pool->pp_smu; - struct dm_pp_clock_for_voltage_req clock_voltage_req = {0}; + uint32_t requested_dcf_clock_in_khz = 0; bool send_request_to_increase = false; bool send_request_to_lower = false; int display_count; @@ -263,8 +263,6 @@ static void dcn1_update_clocks(struct clk_mgr *clk_mgr, // F Clock if (should_set_clock(safe_to_lower, new_clocks->fclk_khz, clk_mgr->clks.fclk_khz)) { clk_mgr->clks.fclk_khz = new_clocks->fclk_khz; - clock_voltage_req.clk_type = DM_PP_CLOCK_TYPE_FCLK; - clock_voltage_req.clocks_in_khz = new_clocks->fclk_khz; smu_req.hard_min_fclk_mhz = new_clocks->fclk_khz / 1000; notify_hard_min_fclk_to_smu(pp_smu, new_clocks->fclk_khz); @@ -293,10 +291,9 @@ static void dcn1_update_clocks(struct clk_mgr *clk_mgr, */ if (send_request_to_increase) { /*use dcfclk to request voltage*/ - clock_voltage_req.clk_type = DM_PP_CLOCK_TYPE_DCFCLK; - clock_voltage_req.clocks_in_khz = dcn_find_dcfclk_suits_all(dc, new_clocks); + requested_dcf_clock_in_khz = dcn_find_dcfclk_suits_all(dc, new_clocks); - notify_hard_min_dcfclk_to_smu(pp_smu, clock_voltage_req.clocks_in_khz); + notify_hard_min_dcfclk_to_smu(pp_smu, requested_dcf_clock_in_khz); if (pp_smu->set_display_requirement) pp_smu->set_display_requirement(&pp_smu->pp_smu, &smu_req); @@ -317,10 +314,9 @@ static void dcn1_update_clocks(struct clk_mgr *clk_mgr, if (!send_request_to_increase && send_request_to_lower) { /*use dcfclk to request voltage*/ - clock_voltage_req.clk_type = DM_PP_CLOCK_TYPE_DCFCLK; - clock_voltage_req.clocks_in_khz = dcn_find_dcfclk_suits_all(dc, new_clocks); + requested_dcf_clock_in_khz = dcn_find_dcfclk_suits_all(dc, new_clocks); - notify_hard_min_dcfclk_to_smu(pp_smu, clock_voltage_req.clocks_in_khz); + notify_hard_min_dcfclk_to_smu(pp_smu, requested_dcf_clock_in_khz); if (pp_smu->set_display_requirement) pp_smu->set_display_requirement(&pp_smu->pp_smu, &smu_req); -- cgit v1.2.3 From 527aa2a0ac241d3ecc02c628db50b16d87e646e0 Mon Sep 17 00:00:00 2001 From: Joerg Roedel Date: Thu, 15 Nov 2018 14:40:29 +0100 Subject: drm/amd/powerplay: Ratelimit all "was not implemented" messages Running kfdtest on an AMD Carizzo flooded the kernel log with thousands of these "was not implemented" messages, making it impossible to see other messages there. Ratelimit the messages to prevent user-space from flooding the kernel log. Signed-off-by: Joerg Roedel Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/powerplay/amd_powerplay.c | 52 +++++++++++++-------------- 1 file changed, 26 insertions(+), 26 deletions(-) (limited to 'drivers/gpu/drm') diff --git a/drivers/gpu/drm/amd/powerplay/amd_powerplay.c b/drivers/gpu/drm/amd/powerplay/amd_powerplay.c index d6aa1d414320..b68c2e0fef01 100644 --- a/drivers/gpu/drm/amd/powerplay/amd_powerplay.c +++ b/drivers/gpu/drm/amd/powerplay/amd_powerplay.c @@ -300,7 +300,7 @@ static int pp_set_clockgating_by_smu(void *handle, uint32_t msg_id) return -EINVAL; if (hwmgr->hwmgr_func->update_clock_gatings == NULL) { - pr_info("%s was not implemented.\n", __func__); + pr_info_ratelimited("%s was not implemented.\n", __func__); return 0; } @@ -387,7 +387,7 @@ static uint32_t pp_dpm_get_sclk(void *handle, bool low) return 0; if (hwmgr->hwmgr_func->get_sclk == NULL) { - pr_info("%s was not implemented.\n", __func__); + pr_info_ratelimited("%s was not implemented.\n", __func__); return 0; } mutex_lock(&hwmgr->smu_lock); @@ -405,7 +405,7 @@ static uint32_t pp_dpm_get_mclk(void *handle, bool low) return 0; if (hwmgr->hwmgr_func->get_mclk == NULL) { - pr_info("%s was not implemented.\n", __func__); + pr_info_ratelimited("%s was not implemented.\n", __func__); return 0; } mutex_lock(&hwmgr->smu_lock); @@ -422,7 +422,7 @@ static void pp_dpm_powergate_vce(void *handle, bool gate) return; if (hwmgr->hwmgr_func->powergate_vce == NULL) { - pr_info("%s was not implemented.\n", __func__); + pr_info_ratelimited("%s was not implemented.\n", __func__); return; } mutex_lock(&hwmgr->smu_lock); @@ -438,7 +438,7 @@ static void pp_dpm_powergate_uvd(void *handle, bool gate) return; if (hwmgr->hwmgr_func->powergate_uvd == NULL) { - pr_info("%s was not implemented.\n", __func__); + pr_info_ratelimited("%s was not implemented.\n", __func__); return; } mutex_lock(&hwmgr->smu_lock); @@ -505,7 +505,7 @@ static void pp_dpm_set_fan_control_mode(void *handle, uint32_t mode) return; if (hwmgr->hwmgr_func->set_fan_control_mode == NULL) { - pr_info("%s was not implemented.\n", __func__); + pr_info_ratelimited("%s was not implemented.\n", __func__); return; } mutex_lock(&hwmgr->smu_lock); @@ -522,7 +522,7 @@ static uint32_t pp_dpm_get_fan_control_mode(void *handle) return 0; if (hwmgr->hwmgr_func->get_fan_control_mode == NULL) { - pr_info("%s was not implemented.\n", __func__); + pr_info_ratelimited("%s was not implemented.\n", __func__); return 0; } mutex_lock(&hwmgr->smu_lock); @@ -540,7 +540,7 @@ static int pp_dpm_set_fan_speed_percent(void *handle, uint32_t percent) return -EINVAL; if (hwmgr->hwmgr_func->set_fan_speed_percent == NULL) { - pr_info("%s was not implemented.\n", __func__); + pr_info_ratelimited("%s was not implemented.\n", __func__); return 0; } mutex_lock(&hwmgr->smu_lock); @@ -558,7 +558,7 @@ static int pp_dpm_get_fan_speed_percent(void *handle, uint32_t *speed) return -EINVAL; if (hwmgr->hwmgr_func->get_fan_speed_percent == NULL) { - pr_info("%s was not implemented.\n", __func__); + pr_info_ratelimited("%s was not implemented.\n", __func__); return 0; } @@ -594,7 +594,7 @@ static int pp_dpm_set_fan_speed_rpm(void *handle, uint32_t rpm) return -EINVAL; if (hwmgr->hwmgr_func->set_fan_speed_rpm == NULL) { - pr_info("%s was not implemented.\n", __func__); + pr_info_ratelimited("%s was not implemented.\n", __func__); return 0; } mutex_lock(&hwmgr->smu_lock); @@ -720,7 +720,7 @@ static int pp_dpm_force_clock_level(void *handle, return -EINVAL; if (hwmgr->hwmgr_func->force_clock_level == NULL) { - pr_info("%s was not implemented.\n", __func__); + pr_info_ratelimited("%s was not implemented.\n", __func__); return 0; } @@ -745,7 +745,7 @@ static int pp_dpm_print_clock_levels(void *handle, return -EINVAL; if (hwmgr->hwmgr_func->print_clock_levels == NULL) { - pr_info("%s was not implemented.\n", __func__); + pr_info_ratelimited("%s was not implemented.\n", __func__); return 0; } mutex_lock(&hwmgr->smu_lock); @@ -763,7 +763,7 @@ static int pp_dpm_get_sclk_od(void *handle) return -EINVAL; if (hwmgr->hwmgr_func->get_sclk_od == NULL) { - pr_info("%s was not implemented.\n", __func__); + pr_info_ratelimited("%s was not implemented.\n", __func__); return 0; } mutex_lock(&hwmgr->smu_lock); @@ -781,7 +781,7 @@ static int pp_dpm_set_sclk_od(void *handle, uint32_t value) return -EINVAL; if (hwmgr->hwmgr_func->set_sclk_od == NULL) { - pr_info("%s was not implemented.\n", __func__); + pr_info_ratelimited("%s was not implemented.\n", __func__); return 0; } @@ -800,7 +800,7 @@ static int pp_dpm_get_mclk_od(void *handle) return -EINVAL; if (hwmgr->hwmgr_func->get_mclk_od == NULL) { - pr_info("%s was not implemented.\n", __func__); + pr_info_ratelimited("%s was not implemented.\n", __func__); return 0; } mutex_lock(&hwmgr->smu_lock); @@ -818,7 +818,7 @@ static int pp_dpm_set_mclk_od(void *handle, uint32_t value) return -EINVAL; if (hwmgr->hwmgr_func->set_mclk_od == NULL) { - pr_info("%s was not implemented.\n", __func__); + pr_info_ratelimited("%s was not implemented.\n", __func__); return 0; } mutex_lock(&hwmgr->smu_lock); @@ -878,7 +878,7 @@ static int pp_get_power_profile_mode(void *handle, char *buf) return -EINVAL; if (hwmgr->hwmgr_func->get_power_profile_mode == NULL) { - pr_info("%s was not implemented.\n", __func__); + pr_info_ratelimited("%s was not implemented.\n", __func__); return snprintf(buf, PAGE_SIZE, "\n"); } @@ -894,7 +894,7 @@ static int pp_set_power_profile_mode(void *handle, long *input, uint32_t size) return ret; if (hwmgr->hwmgr_func->set_power_profile_mode == NULL) { - pr_info("%s was not implemented.\n", __func__); + pr_info_ratelimited("%s was not implemented.\n", __func__); return ret; } @@ -917,7 +917,7 @@ static int pp_odn_edit_dpm_table(void *handle, uint32_t type, long *input, uint3 return -EINVAL; if (hwmgr->hwmgr_func->odn_edit_dpm_table == NULL) { - pr_info("%s was not implemented.\n", __func__); + pr_info_ratelimited("%s was not implemented.\n", __func__); return -EINVAL; } @@ -935,7 +935,7 @@ static int pp_dpm_switch_power_profile(void *handle, return -EINVAL; if (hwmgr->hwmgr_func->set_power_profile_mode == NULL) { - pr_info("%s was not implemented.\n", __func__); + pr_info_ratelimited("%s was not implemented.\n", __func__); return -EINVAL; } @@ -972,7 +972,7 @@ static int pp_set_power_limit(void *handle, uint32_t limit) return -EINVAL; if (hwmgr->hwmgr_func->set_power_limit == NULL) { - pr_info("%s was not implemented.\n", __func__); + pr_info_ratelimited("%s was not implemented.\n", __func__); return -EINVAL; } @@ -1212,7 +1212,7 @@ static int pp_dpm_powergate_mmhub(void *handle) return -EINVAL; if (hwmgr->hwmgr_func->powergate_mmhub == NULL) { - pr_info("%s was not implemented.\n", __func__); + pr_info_ratelimited("%s was not implemented.\n", __func__); return 0; } @@ -1227,7 +1227,7 @@ static int pp_dpm_powergate_gfx(void *handle, bool gate) return 0; if (hwmgr->hwmgr_func->powergate_gfx == NULL) { - pr_info("%s was not implemented.\n", __func__); + pr_info_ratelimited("%s was not implemented.\n", __func__); return 0; } @@ -1242,7 +1242,7 @@ static void pp_dpm_powergate_acp(void *handle, bool gate) return; if (hwmgr->hwmgr_func->powergate_acp == NULL) { - pr_info("%s was not implemented.\n", __func__); + pr_info_ratelimited("%s was not implemented.\n", __func__); return; } @@ -1257,7 +1257,7 @@ static void pp_dpm_powergate_sdma(void *handle, bool gate) return; if (hwmgr->hwmgr_func->powergate_sdma == NULL) { - pr_info("%s was not implemented.\n", __func__); + pr_info_ratelimited("%s was not implemented.\n", __func__); return; } @@ -1303,7 +1303,7 @@ static int pp_notify_smu_enable_pwe(void *handle) return -EINVAL; if (hwmgr->hwmgr_func->smus_notify_pwe == NULL) { - pr_info("%s was not implemented.\n", __func__); + pr_info_ratelimited("%s was not implemented.\n", __func__); return -EINVAL;; } -- cgit v1.2.3 From 82d1a1b128705c4c77a00fd2ea2682867f1dc195 Mon Sep 17 00:00:00 2001 From: Chengming Gui Date: Fri, 16 Nov 2018 14:54:39 +0800 Subject: Revert "drm/amdgpu: use GMC v9 KIQ workaround only for the GFXHUB" (v2) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit With GFXOFF enabled, this patch will cause PCO amdgpu_test failed, but GFXOFF is necessary for PCO, so revert the patch. This reverts commit b83761bb0b09ec11c924afe9d88e458cb16a0372. v2: add a comment for future reference (Alex) Reviewed-by: Huang Rui Reviewed-by: Christian König Signed-off-by: Jack Gui Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/gmc_v9_0.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) (limited to 'drivers/gpu/drm') diff --git a/drivers/gpu/drm/amd/amdgpu/gmc_v9_0.c b/drivers/gpu/drm/amd/amdgpu/gmc_v9_0.c index 811231e4ec53..3a4e5d8d5162 100644 --- a/drivers/gpu/drm/amd/amdgpu/gmc_v9_0.c +++ b/drivers/gpu/drm/amd/amdgpu/gmc_v9_0.c @@ -338,9 +338,12 @@ static void gmc_v9_0_flush_gpu_tlb(struct amdgpu_device *adev, struct amdgpu_vmhub *hub = &adev->vmhub[i]; u32 tmp = gmc_v9_0_get_invalidate_req(vmid, flush_type); - if (i == AMDGPU_GFXHUB && !adev->in_gpu_reset && - adev->gfx.kiq.ring.sched.ready && - (amdgpu_sriov_runtime(adev) || !amdgpu_sriov_vf(adev))) { + /* This is necessary for a HW workaround under SRIOV as well + * as GFXOFF under bare metal + */ + if (adev->gfx.kiq.ring.sched.ready && + (amdgpu_sriov_runtime(adev) || !amdgpu_sriov_vf(adev)) && + !adev->in_gpu_reset) { uint32_t req = hub->vm_inv_eng0_req + eng; uint32_t ack = hub->vm_inv_eng0_ack + eng; -- cgit v1.2.3 From 919a52fc4ca137c871f295224507fa3401e08472 Mon Sep 17 00:00:00 2001 From: Felix Kuehling Date: Fri, 20 Jul 2018 11:37:25 -0400 Subject: drm/amdgpu: Fix oops when pp_funcs->switch_power_profile is unset On Vega20 and other pre-production GPUs, powerplay is not enabled yet. Check for NULL pointers before calling pp_funcs function pointers. Also affects Kaveri. CC: Joerg Roedel Signed-off-by: Felix Kuehling Reviewed-by: Alex Deucher Tested-by: Joerg Roedel Signed-off-by: Alex Deucher Cc: stable@vger.kernel.org --- drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) (limited to 'drivers/gpu/drm') diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.c index c31a8849e9f8..1580ec60b89f 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.c @@ -501,8 +501,11 @@ void amdgpu_amdkfd_set_compute_idle(struct kgd_dev *kgd, bool idle) { struct amdgpu_device *adev = (struct amdgpu_device *)kgd; - amdgpu_dpm_switch_power_profile(adev, - PP_SMC_POWER_PROFILE_COMPUTE, !idle); + if (adev->powerplay.pp_funcs && + adev->powerplay.pp_funcs->switch_power_profile) + amdgpu_dpm_switch_power_profile(adev, + PP_SMC_POWER_PROFILE_COMPUTE, + !idle); } bool amdgpu_amdkfd_is_kfd_vmid(struct amdgpu_device *adev, u32 vmid) -- cgit v1.2.3 From 009dd011762925e5e03a59282b1785214f8470e0 Mon Sep 17 00:00:00 2001 From: Evan Quan Date: Mon, 19 Nov 2018 12:03:24 +0800 Subject: drm/amd/powerplay: disable Vega20 DS related features Disable these features on Vega20 for now. Signed-off-by: Evan Quan Acked-by: Feifei Xu Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/powerplay/hwmgr/vega20_hwmgr.c | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) (limited to 'drivers/gpu/drm') diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/vega20_hwmgr.c b/drivers/gpu/drm/amd/powerplay/hwmgr/vega20_hwmgr.c index 99861f32b1f9..397ee88fec03 100644 --- a/drivers/gpu/drm/amd/powerplay/hwmgr/vega20_hwmgr.c +++ b/drivers/gpu/drm/amd/powerplay/hwmgr/vega20_hwmgr.c @@ -75,7 +75,17 @@ static void vega20_set_default_registry_data(struct pp_hwmgr *hwmgr) data->phy_clk_quad_eqn_b = PPREGKEY_VEGA20QUADRATICEQUATION_DFLT; data->phy_clk_quad_eqn_c = PPREGKEY_VEGA20QUADRATICEQUATION_DFLT; - data->registry_data.disallowed_features = 0x0; + /* + * Disable the following features for now: + * GFXCLK DS + * SOCLK DS + * LCLK DS + * DCEFCLK DS + * FCLK DS + * MP1CLK DS + * MP0CLK DS + */ + data->registry_data.disallowed_features = 0xE0041C00; data->registry_data.od_state_in_dc_support = 0; data->registry_data.thermal_support = 1; data->registry_data.skip_baco_hardware = 0; -- cgit v1.2.3 From 8d4d7c58994759bbd9f4fec32d88bf0e0b89302e Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 19 Nov 2018 12:55:12 +0100 Subject: drm/amdgpu: Add missing firmware entry for HAINAN MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Due to lack of MODULE_FIRMWARE() with hainan_mc.bin, the driver doesn't work properly in initrd. Let's add it. Bugzilla: https://bugzilla.suse.com/show_bug.cgi?id=1116239 Fixes: 8eaf2b1faaf4 ("drm/amdgpu: switch firmware path for SI parts") Cc: Reviewed-by: Christian König Signed-off-by: Takashi Iwai Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/gmc_v6_0.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/gpu/drm') diff --git a/drivers/gpu/drm/amd/amdgpu/gmc_v6_0.c b/drivers/gpu/drm/amd/amdgpu/gmc_v6_0.c index e1c2b4e9c7b2..73ad02aea2b2 100644 --- a/drivers/gpu/drm/amd/amdgpu/gmc_v6_0.c +++ b/drivers/gpu/drm/amd/amdgpu/gmc_v6_0.c @@ -46,6 +46,7 @@ MODULE_FIRMWARE("amdgpu/tahiti_mc.bin"); MODULE_FIRMWARE("amdgpu/pitcairn_mc.bin"); MODULE_FIRMWARE("amdgpu/verde_mc.bin"); MODULE_FIRMWARE("amdgpu/oland_mc.bin"); +MODULE_FIRMWARE("amdgpu/hainan_mc.bin"); MODULE_FIRMWARE("amdgpu/si58_mc.bin"); #define MC_SEQ_MISC0__MT__MASK 0xf0000000 -- cgit v1.2.3 From a4233cc944d1b7125d906f1fa276bda3df48df0c Mon Sep 17 00:00:00 2001 From: "Greathouse, Joseph" Date: Mon, 19 Nov 2018 16:59:28 +0000 Subject: drm/amd/pp: handle negative values when reading OD Reading the sysfs files pp_sclk_od and pp_mclk_od return the percentage difference between the VBIOS-provided default frequency and the current (possibly user-set) frequency in the highest SCLK and MCLK DPM states, respectively. Writing to these files provides an easy mechanism for setting a higher-than-default maximum frequency. We normally only allow values >= 0 to be written here. However, with the addition of pp_od_clk_voltage, we now allow users to set custom DPM tables. If they then set the maximum DPM state to something less than the default, later reads of pp_*_od should return a negative value. The highest DPM state is now less than the VBIOS-provided default, so the percentage is negative. The math to calculate this was originally performed with unsigned values, meaning reads that should return negative values returned meaningless data. This patch corrects that issue and normalizes how all of the calculations are done across the various hwmgr types. Acked-by: Alex Deucher Signed-off-by: Joseph Greathouse Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/powerplay/hwmgr/smu7_hwmgr.c | 20 ++++++++--------- drivers/gpu/drm/amd/powerplay/hwmgr/vega10_hwmgr.c | 25 +++++++++------------- drivers/gpu/drm/amd/powerplay/hwmgr/vega12_hwmgr.c | 23 +++++++++----------- drivers/gpu/drm/amd/powerplay/hwmgr/vega20_hwmgr.c | 18 +++++++++------- 4 files changed, 40 insertions(+), 46 deletions(-) (limited to 'drivers/gpu/drm') diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/smu7_hwmgr.c b/drivers/gpu/drm/amd/powerplay/hwmgr/smu7_hwmgr.c index ed35ec0341e6..88f6b35ea6fe 100644 --- a/drivers/gpu/drm/amd/powerplay/hwmgr/smu7_hwmgr.c +++ b/drivers/gpu/drm/amd/powerplay/hwmgr/smu7_hwmgr.c @@ -4525,12 +4525,12 @@ static int smu7_get_sclk_od(struct pp_hwmgr *hwmgr) struct smu7_single_dpm_table *sclk_table = &(data->dpm_table.sclk_table); struct smu7_single_dpm_table *golden_sclk_table = &(data->golden_dpm_table.sclk_table); - int value; + int value = sclk_table->dpm_levels[sclk_table->count - 1].value; + int golden_value = golden_sclk_table->dpm_levels + [golden_sclk_table->count - 1].value; - value = (sclk_table->dpm_levels[sclk_table->count - 1].value - - golden_sclk_table->dpm_levels[golden_sclk_table->count - 1].value) * - 100 / - golden_sclk_table->dpm_levels[golden_sclk_table->count - 1].value; + value -= golden_value; + value = DIV_ROUND_UP(value * 100, golden_value); return value; } @@ -4567,12 +4567,12 @@ static int smu7_get_mclk_od(struct pp_hwmgr *hwmgr) struct smu7_single_dpm_table *mclk_table = &(data->dpm_table.mclk_table); struct smu7_single_dpm_table *golden_mclk_table = &(data->golden_dpm_table.mclk_table); - int value; + int value = mclk_table->dpm_levels[mclk_table->count - 1].value; + int golden_value = golden_mclk_table->dpm_levels + [golden_mclk_table->count - 1].value; - value = (mclk_table->dpm_levels[mclk_table->count - 1].value - - golden_mclk_table->dpm_levels[golden_mclk_table->count - 1].value) * - 100 / - golden_mclk_table->dpm_levels[golden_mclk_table->count - 1].value; + value -= golden_value; + value = DIV_ROUND_UP(value * 100, golden_value); return value; } diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/vega10_hwmgr.c b/drivers/gpu/drm/amd/powerplay/hwmgr/vega10_hwmgr.c index 8c4db86bb4b7..e2bc6e0c229f 100644 --- a/drivers/gpu/drm/amd/powerplay/hwmgr/vega10_hwmgr.c +++ b/drivers/gpu/drm/amd/powerplay/hwmgr/vega10_hwmgr.c @@ -4522,15 +4522,13 @@ static int vega10_get_sclk_od(struct pp_hwmgr *hwmgr) struct vega10_single_dpm_table *sclk_table = &(data->dpm_table.gfx_table); struct vega10_single_dpm_table *golden_sclk_table = &(data->golden_dpm_table.gfx_table); - int value; - - value = (sclk_table->dpm_levels[sclk_table->count - 1].value - - golden_sclk_table->dpm_levels - [golden_sclk_table->count - 1].value) * - 100 / - golden_sclk_table->dpm_levels + int value = sclk_table->dpm_levels[sclk_table->count - 1].value; + int golden_value = golden_sclk_table->dpm_levels [golden_sclk_table->count - 1].value; + value -= golden_value; + value = DIV_ROUND_UP(value * 100, golden_value); + return value; } @@ -4575,16 +4573,13 @@ static int vega10_get_mclk_od(struct pp_hwmgr *hwmgr) struct vega10_single_dpm_table *mclk_table = &(data->dpm_table.mem_table); struct vega10_single_dpm_table *golden_mclk_table = &(data->golden_dpm_table.mem_table); - int value; - - value = (mclk_table->dpm_levels - [mclk_table->count - 1].value - - golden_mclk_table->dpm_levels - [golden_mclk_table->count - 1].value) * - 100 / - golden_mclk_table->dpm_levels + int value = mclk_table->dpm_levels[mclk_table->count - 1].value; + int golden_value = golden_mclk_table->dpm_levels [golden_mclk_table->count - 1].value; + value -= golden_value; + value = DIV_ROUND_UP(value * 100, golden_value); + return value; } diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/vega12_hwmgr.c b/drivers/gpu/drm/amd/powerplay/hwmgr/vega12_hwmgr.c index 74bc37308dc0..54364444ecd1 100644 --- a/drivers/gpu/drm/amd/powerplay/hwmgr/vega12_hwmgr.c +++ b/drivers/gpu/drm/amd/powerplay/hwmgr/vega12_hwmgr.c @@ -2243,12 +2243,12 @@ static int vega12_get_sclk_od(struct pp_hwmgr *hwmgr) struct vega12_single_dpm_table *sclk_table = &(data->dpm_table.gfx_table); struct vega12_single_dpm_table *golden_sclk_table = &(data->golden_dpm_table.gfx_table); - int value; + int value = sclk_table->dpm_levels[sclk_table->count - 1].value; + int golden_value = golden_sclk_table->dpm_levels + [golden_sclk_table->count - 1].value; - value = (sclk_table->dpm_levels[sclk_table->count - 1].value - - golden_sclk_table->dpm_levels[golden_sclk_table->count - 1].value) * - 100 / - golden_sclk_table->dpm_levels[golden_sclk_table->count - 1].value; + value -= golden_value; + value = DIV_ROUND_UP(value * 100, golden_value); return value; } @@ -2264,16 +2264,13 @@ static int vega12_get_mclk_od(struct pp_hwmgr *hwmgr) struct vega12_single_dpm_table *mclk_table = &(data->dpm_table.mem_table); struct vega12_single_dpm_table *golden_mclk_table = &(data->golden_dpm_table.mem_table); - int value; - - value = (mclk_table->dpm_levels - [mclk_table->count - 1].value - - golden_mclk_table->dpm_levels - [golden_mclk_table->count - 1].value) * - 100 / - golden_mclk_table->dpm_levels + int value = mclk_table->dpm_levels[mclk_table->count - 1].value; + int golden_value = golden_mclk_table->dpm_levels [golden_mclk_table->count - 1].value; + value -= golden_value; + value = DIV_ROUND_UP(value * 100, golden_value); + return value; } diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/vega20_hwmgr.c b/drivers/gpu/drm/amd/powerplay/hwmgr/vega20_hwmgr.c index 397ee88fec03..b4eadd47f3a4 100644 --- a/drivers/gpu/drm/amd/powerplay/hwmgr/vega20_hwmgr.c +++ b/drivers/gpu/drm/amd/powerplay/hwmgr/vega20_hwmgr.c @@ -1323,12 +1323,13 @@ static int vega20_get_sclk_od( &(data->dpm_table.gfx_table); struct vega20_single_dpm_table *golden_sclk_table = &(data->golden_dpm_table.gfx_table); - int value; + int value = sclk_table->dpm_levels[sclk_table->count - 1].value; + int golden_value = golden_sclk_table->dpm_levels + [golden_sclk_table->count - 1].value; /* od percentage */ - value = DIV_ROUND_UP((sclk_table->dpm_levels[sclk_table->count - 1].value - - golden_sclk_table->dpm_levels[golden_sclk_table->count - 1].value) * 100, - golden_sclk_table->dpm_levels[golden_sclk_table->count - 1].value); + value -= golden_value; + value = DIV_ROUND_UP(value * 100, golden_value); return value; } @@ -1368,12 +1369,13 @@ static int vega20_get_mclk_od( &(data->dpm_table.mem_table); struct vega20_single_dpm_table *golden_mclk_table = &(data->golden_dpm_table.mem_table); - int value; + int value = mclk_table->dpm_levels[mclk_table->count - 1].value; + int golden_value = golden_mclk_table->dpm_levels + [golden_mclk_table->count - 1].value; /* od percentage */ - value = DIV_ROUND_UP((mclk_table->dpm_levels[mclk_table->count - 1].value - - golden_mclk_table->dpm_levels[golden_mclk_table->count - 1].value) * 100, - golden_mclk_table->dpm_levels[golden_mclk_table->count - 1].value); + value -= golden_value; + value = DIV_ROUND_UP(value * 100, golden_value); return value; } -- cgit v1.2.3 From 4e6c6fc19d3ffc9a60df3a2abf46bf3b08c7a329 Mon Sep 17 00:00:00 2001 From: Yong Zhao Date: Mon, 4 Jun 2018 14:33:13 -0400 Subject: drm/amdkfd: Replace mqd with mqd_mgr as the variable name for mqd_manager This will make reading code much easier. This fixes a few spots missed in a previous commit with the same title. Signed-off-by: Yong Zhao Reviewed-by: Felix Kuehling Signed-off-by: Felix Kuehling Reviewed-by: Alex Deucher Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'drivers/gpu/drm') diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.c b/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.c index fb9d66ea13b7..d38efbbcd671 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.c @@ -1547,7 +1547,7 @@ static int get_wave_state(struct device_queue_manager *dqm, u32 *ctl_stack_used_size, u32 *save_area_used_size) { - struct mqd_manager *mqd; + struct mqd_manager *mqd_mgr; int r; dqm_lock(dqm); @@ -1558,19 +1558,19 @@ static int get_wave_state(struct device_queue_manager *dqm, goto dqm_unlock; } - mqd = dqm->ops.get_mqd_manager(dqm, KFD_MQD_TYPE_COMPUTE); - if (!mqd) { + mqd_mgr = dqm->ops.get_mqd_manager(dqm, KFD_MQD_TYPE_COMPUTE); + if (!mqd_mgr) { r = -ENOMEM; goto dqm_unlock; } - if (!mqd->get_wave_state) { + if (!mqd_mgr->get_wave_state) { r = -EINVAL; goto dqm_unlock; } - r = mqd->get_wave_state(mqd, q->mqd, ctl_stack, ctl_stack_used_size, - save_area_used_size); + r = mqd_mgr->get_wave_state(mqd_mgr, q->mqd, ctl_stack, + ctl_stack_used_size, save_area_used_size); dqm_unlock: dqm_unlock(dqm); -- cgit v1.2.3 From 846a44d7e918a4012715f79164bf71b9a6840657 Mon Sep 17 00:00:00 2001 From: Gang Ba Date: Wed, 5 Sep 2018 11:27:14 -0400 Subject: drm/amdkfd: Added Vega12 and Polaris12 for KFD. Add Vega12 and Polaris12 device info and device IDs to KFD. Signed-off-by: Gang Ba Reviewed-by: Felix Kuehling Signed-off-by: Felix Kuehling Reviewed-by: Alex Deucher Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.c | 2 + drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gpuvm.c | 3 +- drivers/gpu/drm/amd/amdkfd/kfd_crat.c | 6 +++ drivers/gpu/drm/amd/amdkfd/kfd_device.c | 45 ++++++++++++++++++++++ .../gpu/drm/amd/amdkfd/kfd_device_queue_manager.c | 2 + drivers/gpu/drm/amd/amdkfd/kfd_flat_memory.c | 2 + drivers/gpu/drm/amd/amdkfd/kfd_kernel_queue.c | 2 + drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager.c | 2 + drivers/gpu/drm/amd/amdkfd/kfd_packet_manager.c | 2 + drivers/gpu/drm/amd/amdkfd/kfd_topology.c | 2 + 10 files changed, 67 insertions(+), 1 deletion(-) (limited to 'drivers/gpu/drm') diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.c index 60f9a87e9c74..a9c7597963e6 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.c @@ -73,9 +73,11 @@ void amdgpu_amdkfd_device_probe(struct amdgpu_device *adev) case CHIP_FIJI: case CHIP_POLARIS10: case CHIP_POLARIS11: + case CHIP_POLARIS12: kfd2kgd = amdgpu_amdkfd_gfx_8_0_get_functions(); break; case CHIP_VEGA10: + case CHIP_VEGA12: case CHIP_VEGA20: case CHIP_RAVEN: kfd2kgd = amdgpu_amdkfd_gfx_9_0_get_functions(); diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gpuvm.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gpuvm.c index df0a059565f9..9a1b2b26a888 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gpuvm.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gpuvm.c @@ -1199,7 +1199,8 @@ int amdgpu_amdkfd_gpuvm_alloc_memory_of_gpu( byte_align = (adev->family == AMDGPU_FAMILY_VI && adev->asic_type != CHIP_FIJI && adev->asic_type != CHIP_POLARIS10 && - adev->asic_type != CHIP_POLARIS11) ? + adev->asic_type != CHIP_POLARIS11 && + adev->asic_type != CHIP_POLARIS12) ? VI_BO_SIZE_ALIGN : 1; mapping_flags = AMDGPU_VM_PAGE_READABLE; diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_crat.c b/drivers/gpu/drm/amd/amdkfd/kfd_crat.c index 3783d122f283..c02adbbeef2a 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_crat.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_crat.c @@ -133,6 +133,7 @@ static struct kfd_gpu_cache_info carrizo_cache_info[] = { #define fiji_cache_info carrizo_cache_info #define polaris10_cache_info carrizo_cache_info #define polaris11_cache_info carrizo_cache_info +#define polaris12_cache_info carrizo_cache_info /* TODO - check & update Vega10 cache details */ #define vega10_cache_info carrizo_cache_info #define raven_cache_info carrizo_cache_info @@ -647,7 +648,12 @@ static int kfd_fill_gpu_cache_info(struct kfd_dev *kdev, pcache_info = polaris11_cache_info; num_of_cache_types = ARRAY_SIZE(polaris11_cache_info); break; + case CHIP_POLARIS12: + pcache_info = polaris12_cache_info; + num_of_cache_types = ARRAY_SIZE(polaris12_cache_info); + break; case CHIP_VEGA10: + case CHIP_VEGA12: case CHIP_VEGA20: pcache_info = vega10_cache_info; num_of_cache_types = ARRAY_SIZE(vega10_cache_info); diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_device.c b/drivers/gpu/drm/amd/amdkfd/kfd_device.c index c004647c8cb4..9ed14a11afa2 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_device.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_device.c @@ -205,6 +205,22 @@ static const struct kfd_device_info polaris11_device_info = { .num_sdma_queues_per_engine = 2, }; +static const struct kfd_device_info polaris12_device_info = { + .asic_family = CHIP_POLARIS12, + .max_pasid_bits = 16, + .max_no_of_hqd = 24, + .doorbell_size = 4, + .ih_ring_entry_size = 4 * sizeof(uint32_t), + .event_interrupt_class = &event_interrupt_class_cik, + .num_of_watch_points = 4, + .mqd_size_aligned = MQD_SIZE_ALIGNED, + .supports_cwsr = true, + .needs_iommu_device = false, + .needs_pci_atomics = true, + .num_sdma_engines = 2, + .num_sdma_queues_per_engine = 2, +}; + static const struct kfd_device_info vega10_device_info = { .asic_family = CHIP_VEGA10, .max_pasid_bits = 16, @@ -237,6 +253,22 @@ static const struct kfd_device_info vega10_vf_device_info = { .num_sdma_queues_per_engine = 2, }; +static const struct kfd_device_info vega12_device_info = { + .asic_family = CHIP_VEGA12, + .max_pasid_bits = 16, + .max_no_of_hqd = 24, + .doorbell_size = 8, + .ih_ring_entry_size = 8 * sizeof(uint32_t), + .event_interrupt_class = &event_interrupt_class_v9, + .num_of_watch_points = 4, + .mqd_size_aligned = MQD_SIZE_ALIGNED, + .supports_cwsr = true, + .needs_iommu_device = false, + .needs_pci_atomics = false, + .num_sdma_engines = 2, + .num_sdma_queues_per_engine = 2, +}; + static const struct kfd_device_info vega20_device_info = { .asic_family = CHIP_VEGA20, .max_pasid_bits = 16, @@ -331,6 +363,14 @@ static const struct kfd_deviceid supported_devices[] = { { 0x67EB, &polaris11_device_info }, /* Polaris11 */ { 0x67EF, &polaris11_device_info }, /* Polaris11 */ { 0x67FF, &polaris11_device_info }, /* Polaris11 */ + { 0x6980, &polaris12_device_info }, /* Polaris12 */ + { 0x6981, &polaris12_device_info }, /* Polaris12 */ + { 0x6985, &polaris12_device_info }, /* Polaris12 */ + { 0x6986, &polaris12_device_info }, /* Polaris12 */ + { 0x6987, &polaris12_device_info }, /* Polaris12 */ + { 0x6995, &polaris12_device_info }, /* Polaris12 */ + { 0x6997, &polaris12_device_info }, /* Polaris12 */ + { 0x699F, &polaris12_device_info }, /* Polaris12 */ { 0x6860, &vega10_device_info }, /* Vega10 */ { 0x6861, &vega10_device_info }, /* Vega10 */ { 0x6862, &vega10_device_info }, /* Vega10 */ @@ -340,6 +380,11 @@ static const struct kfd_deviceid supported_devices[] = { { 0x6868, &vega10_device_info }, /* Vega10 */ { 0x686C, &vega10_vf_device_info }, /* Vega10 vf*/ { 0x687F, &vega10_device_info }, /* Vega10 */ + { 0x69A0, &vega12_device_info }, /* Vega12 */ + { 0x69A1, &vega12_device_info }, /* Vega12 */ + { 0x69A2, &vega12_device_info }, /* Vega12 */ + { 0x69A3, &vega12_device_info }, /* Vega12 */ + { 0x69AF, &vega12_device_info }, /* Vega12 */ { 0x66a0, &vega20_device_info }, /* Vega20 */ { 0x66a1, &vega20_device_info }, /* Vega20 */ { 0x66a2, &vega20_device_info }, /* Vega20 */ diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.c b/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.c index d38efbbcd671..8372556b52eb 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.c @@ -1741,10 +1741,12 @@ struct device_queue_manager *device_queue_manager_init(struct kfd_dev *dev) case CHIP_FIJI: case CHIP_POLARIS10: case CHIP_POLARIS11: + case CHIP_POLARIS12: device_queue_manager_init_vi_tonga(&dqm->asic_ops); break; case CHIP_VEGA10: + case CHIP_VEGA12: case CHIP_VEGA20: case CHIP_RAVEN: device_queue_manager_init_v9(&dqm->asic_ops); diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_flat_memory.c b/drivers/gpu/drm/amd/amdkfd/kfd_flat_memory.c index 3d66cec414af..213ea5454d11 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_flat_memory.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_flat_memory.c @@ -397,9 +397,11 @@ int kfd_init_apertures(struct kfd_process *process) case CHIP_FIJI: case CHIP_POLARIS10: case CHIP_POLARIS11: + case CHIP_POLARIS12: kfd_init_apertures_vi(pdd, id); break; case CHIP_VEGA10: + case CHIP_VEGA12: case CHIP_VEGA20: case CHIP_RAVEN: kfd_init_apertures_v9(pdd, id); diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_kernel_queue.c b/drivers/gpu/drm/amd/amdkfd/kfd_kernel_queue.c index 6c31f7370193..f1596881f20a 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_kernel_queue.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_kernel_queue.c @@ -313,6 +313,7 @@ struct kernel_queue *kernel_queue_init(struct kfd_dev *dev, case CHIP_FIJI: case CHIP_POLARIS10: case CHIP_POLARIS11: + case CHIP_POLARIS12: kernel_queue_init_vi(&kq->ops_asic_specific); break; @@ -322,6 +323,7 @@ struct kernel_queue *kernel_queue_init(struct kfd_dev *dev, break; case CHIP_VEGA10: + case CHIP_VEGA12: case CHIP_VEGA20: case CHIP_RAVEN: kernel_queue_init_v9(&kq->ops_asic_specific); diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager.c b/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager.c index 6910028010d6..aed9b9b82213 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager.c @@ -38,8 +38,10 @@ struct mqd_manager *mqd_manager_init(enum KFD_MQD_TYPE type, case CHIP_FIJI: case CHIP_POLARIS10: case CHIP_POLARIS11: + case CHIP_POLARIS12: return mqd_manager_init_vi_tonga(type, dev); case CHIP_VEGA10: + case CHIP_VEGA12: case CHIP_VEGA20: case CHIP_RAVEN: return mqd_manager_init_v9(type, dev); diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_packet_manager.c b/drivers/gpu/drm/amd/amdkfd/kfd_packet_manager.c index c6080ed3b6a7..045a229436a0 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_packet_manager.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_packet_manager.c @@ -226,9 +226,11 @@ int pm_init(struct packet_manager *pm, struct device_queue_manager *dqm) case CHIP_FIJI: case CHIP_POLARIS10: case CHIP_POLARIS11: + case CHIP_POLARIS12: pm->pmf = &kfd_vi_pm_funcs; break; case CHIP_VEGA10: + case CHIP_VEGA12: case CHIP_VEGA20: case CHIP_RAVEN: pm->pmf = &kfd_v9_pm_funcs; diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_topology.c b/drivers/gpu/drm/amd/amdkfd/kfd_topology.c index c73b4ff61f99..aa793fcbbdcc 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_topology.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_topology.c @@ -1272,12 +1272,14 @@ int kfd_topology_add_device(struct kfd_dev *gpu) case CHIP_FIJI: case CHIP_POLARIS10: case CHIP_POLARIS11: + case CHIP_POLARIS12: pr_debug("Adding doorbell packet type capability\n"); dev->node_props.capability |= ((HSA_CAP_DOORBELL_TYPE_1_0 << HSA_CAP_DOORBELL_TYPE_TOTALBITS_SHIFT) & HSA_CAP_DOORBELL_TYPE_TOTALBITS_MASK); break; case CHIP_VEGA10: + case CHIP_VEGA12: case CHIP_VEGA20: case CHIP_RAVEN: dev->node_props.capability |= ((HSA_CAP_DOORBELL_TYPE_2_0 << -- cgit v1.2.3 From 00557f4131473c0012f8d8c468987468b42d2eb2 Mon Sep 17 00:00:00 2001 From: Yong Zhao Date: Wed, 17 Oct 2018 12:03:48 -0400 Subject: drm/amdkfd: Adjust the debug message in KFD ISR This makes debug message get printed even when there is early return. Signed-off-by: Yong Zhao Reviewed-by: Felix Kuehling Signed-off-by: Felix Kuehling Reviewed-by: Alex Deucher Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdkfd/kfd_int_process_v9.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) (limited to 'drivers/gpu/drm') diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_int_process_v9.c b/drivers/gpu/drm/amd/amdkfd/kfd_int_process_v9.c index f836897bbf58..849786492447 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_int_process_v9.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_int_process_v9.c @@ -39,20 +39,20 @@ static bool event_interrupt_isr_v9(struct kfd_dev *dev, vmid > dev->vm_info.last_vmid_kfd) return 0; - /* If there is no valid PASID, it's likely a firmware bug */ - pasid = SOC15_PASID_FROM_IH_ENTRY(ih_ring_entry); - if (WARN_ONCE(pasid == 0, "FW bug: No PASID in KFD interrupt")) - return 0; - source_id = SOC15_SOURCE_ID_FROM_IH_ENTRY(ih_ring_entry); client_id = SOC15_CLIENT_ID_FROM_IH_ENTRY(ih_ring_entry); + pasid = SOC15_PASID_FROM_IH_ENTRY(ih_ring_entry); - pr_debug("client id 0x%x, source id %d, pasid 0x%x. raw data:\n", - client_id, source_id, pasid); + pr_debug("client id 0x%x, source id %d, vmid %d, pasid 0x%x. raw data:\n", + client_id, source_id, vmid, pasid); pr_debug("%8X, %8X, %8X, %8X, %8X, %8X, %8X, %8X.\n", data[0], data[1], data[2], data[3], data[4], data[5], data[6], data[7]); + /* If there is no valid PASID, it's likely a firmware bug */ + if (WARN_ONCE(pasid == 0, "FW bug: No PASID in KFD interrupt")) + return 0; + /* Interrupt types we care about: various signals and faults. * They will be forwarded to a work queue (see below). */ -- cgit v1.2.3 From a53a11a835b657c99e740712f7c95625143afcd8 Mon Sep 17 00:00:00 2001 From: Yong Zhao Date: Wed, 17 Oct 2018 12:24:02 -0400 Subject: drm/amdkfd: Workaround PASID missing in gfx9 interrupt payload under non HWS This is a known gfx9 HW issue, and this change can perfectly workaround the issue. Signed-off-by: Yong Zhao Reviewed-by: Felix Kuehling Signed-off-by: Felix Kuehling Acked-by: Alex Deucher Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdkfd/kfd_int_process_v9.c | 25 ++++++++++++++++++++++--- 1 file changed, 22 insertions(+), 3 deletions(-) (limited to 'drivers/gpu/drm') diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_int_process_v9.c b/drivers/gpu/drm/amd/amdkfd/kfd_int_process_v9.c index 849786492447..a85904ad0d5f 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_int_process_v9.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_int_process_v9.c @@ -23,7 +23,7 @@ #include "kfd_priv.h" #include "kfd_events.h" #include "soc15_int.h" - +#include "kfd_device_queue_manager.h" static bool event_interrupt_isr_v9(struct kfd_dev *dev, const uint32_t *ih_ring_entry, @@ -43,14 +43,33 @@ static bool event_interrupt_isr_v9(struct kfd_dev *dev, client_id = SOC15_CLIENT_ID_FROM_IH_ENTRY(ih_ring_entry); pasid = SOC15_PASID_FROM_IH_ENTRY(ih_ring_entry); + /* This is a known issue for gfx9. Under non HWS, pasid is not set + * in the interrupt payload, so we need to find out the pasid on our + * own. + */ + if (!pasid && dev->dqm->sched_policy == KFD_SCHED_POLICY_NO_HWS) { + const uint32_t pasid_mask = 0xffff; + + *patched_flag = true; + memcpy(patched_ihre, ih_ring_entry, + dev->device_info->ih_ring_entry_size); + + pasid = dev->kfd2kgd->get_atc_vmid_pasid_mapping_pasid( + dev->kgd, vmid); + + /* Patch the pasid field */ + patched_ihre[3] = cpu_to_le32((le32_to_cpu(patched_ihre[3]) + & ~pasid_mask) | pasid); + } + pr_debug("client id 0x%x, source id %d, vmid %d, pasid 0x%x. raw data:\n", client_id, source_id, vmid, pasid); pr_debug("%8X, %8X, %8X, %8X, %8X, %8X, %8X, %8X.\n", data[0], data[1], data[2], data[3], data[4], data[5], data[6], data[7]); - /* If there is no valid PASID, it's likely a firmware bug */ - if (WARN_ONCE(pasid == 0, "FW bug: No PASID in KFD interrupt")) + /* If there is no valid PASID, it's likely a bug */ + if (WARN_ONCE(pasid == 0, "Bug: No PASID in KFD interrupt")) return 0; /* Interrupt types we care about: various signals and faults. -- cgit v1.2.3 From 5814cef8079bd1118fc14ff9231d487f4d539d34 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Fri, 16 Nov 2018 14:46:51 -0500 Subject: drm/amdgpu/gfx: use proper offset define for MEC doorbells Looks like a copy paste typo. Reviewed-by: Felix Kuehling Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/gfx_v9_0.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/gpu/drm') diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v9_0.c b/drivers/gpu/drm/amd/amdgpu/gfx_v9_0.c index c27caa144c57..e409fbf67fe7 100644 --- a/drivers/gpu/drm/amd/amdgpu/gfx_v9_0.c +++ b/drivers/gpu/drm/amd/amdgpu/gfx_v9_0.c @@ -1566,7 +1566,7 @@ static int gfx_v9_0_compute_ring_init(struct amdgpu_device *adev, int ring_id, ring->ring_obj = NULL; ring->use_doorbell = true; - ring->doorbell_index = (AMDGPU_DOORBELL_MEC_RING0 + ring_id) << 1; + ring->doorbell_index = (AMDGPU_DOORBELL64_MEC_RING0 + ring_id) << 1; ring->eop_gpu_addr = adev->gfx.mec.hpd_eop_gpu_addr + (ring_id * GFX9_MEC_HPD_SIZE); sprintf(ring->name, "comp_%d.%d.%d", ring->me, ring->pipe, ring->queue); -- cgit v1.2.3 From 85744e9c100696d3f210e80b85fd56dd19767c81 Mon Sep 17 00:00:00 2001 From: Trigger Huang Date: Wed, 14 Nov 2018 10:44:50 +0800 Subject: drm/scheduler: Fix bad job be re-processed in TDR MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit A bad job is the one triggered TDR(In the current amdgpu's implementation, actually all the jobs in the current joq-queue will be treated as bad jobs). In the recovery process, its fence will be fake signaled and as a result, the work behind will be scheduled to delete it from the mirror list, but if the TDR process is invoked before the work's execution, then this bad job might be processed again and the call dma_fence_set_error to its fence in TDR process will lead to kernel warning trace: [ 143.033605] WARNING: CPU: 2 PID: 53 at ./include/linux/dma-fence.h:437 amddrm_sched_job_recovery+0x1af/0x1c0 [amd_sched] kernel: [ 143.033606] Modules linked in: amdgpu(OE) amdchash(OE) amdttm(OE) amd_sched(OE) amdkcl(OE) amd_iommu_v2 drm_kms_helper drm i2c_algo_bit fb_sys_fops syscopyarea sysfillrect sysimgblt kvm_intel kvm irqbypass crct10dif_pclmul crc32_pclmul ghash_clmulni_intel pcbc aesni_intel aes_x86_64 snd_hda_codec_generic crypto_simd glue_helper cryptd snd_hda_intel snd_hda_codec snd_hda_core snd_hwdep snd_pcm snd_seq_midi snd_seq_midi_event snd_rawmidi snd_seq joydev snd_seq_device snd_timer snd soundcore binfmt_misc input_leds mac_hid serio_raw nfsd auth_rpcgss nfs_acl lockd grace sunrpc sch_fq_codel parport_pc ppdev lp parport ip_tables x_tables autofs4 8139too floppy psmouse 8139cp mii i2c_piix4 pata_acpi [ 143.033649] CPU: 2 PID: 53 Comm: kworker/2:1 Tainted: G OE 4.15.0-20-generic #21-Ubuntu [ 143.033650] Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS Ubuntu-1.8.2-1ubuntu1 04/01/2014 [ 143.033653] Workqueue: events drm_sched_job_timedout [amd_sched] [ 143.033656] RIP: 0010:amddrm_sched_job_recovery+0x1af/0x1c0 [amd_sched] [ 143.033657] RSP: 0018:ffffa9f880fe7d48 EFLAGS: 00010202 [ 143.033659] RAX: 0000000000000007 RBX: ffff9b98f2b24c00 RCX: ffff9b98efef4f08 [ 143.033660] RDX: ffff9b98f2b27400 RSI: ffff9b98f2b24c50 RDI: ffff9b98efef4f18 [ 143.033660] RBP: ffffa9f880fe7d98 R08: 0000000000000001 R09: 00000000000002b6 [ 143.033661] R10: 0000000000000000 R11: 0000000000000000 R12: ffff9b98efef3430 [ 143.033662] R13: ffff9b98efef4d80 R14: ffff9b98efef4e98 R15: ffff9b98eaf91c00 [ 143.033663] FS: 0000000000000000(0000) GS:ffff9b98ffd00000(0000) knlGS:0000000000000000 [ 143.033664] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 [ 143.033665] CR2: 00007fc49c96d470 CR3: 000000001400a005 CR4: 00000000003606e0 [ 143.033669] DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000 [ 143.033669] DR3: 0000000000000000 DR6: 00000000fffe0ff0 DR7: 0000000000000400 [ 143.033670] Call Trace: [ 143.033744] amdgpu_device_gpu_recover+0x144/0x820 [amdgpu] [ 143.033788] amdgpu_job_timedout+0x9b/0xa0 [amdgpu] [ 143.033791] drm_sched_job_timedout+0xcc/0x150 [amd_sched] [ 143.033795] process_one_work+0x1de/0x410 [ 143.033797] worker_thread+0x32/0x410 [ 143.033799] kthread+0x121/0x140 [ 143.033801] ? process_one_work+0x410/0x410 [ 143.033803] ? kthread_create_worker_on_cpu+0x70/0x70 [ 143.033806] ret_from_fork+0x35/0x40 So just delete the bad job from mirror list directly Changes in v3: - Add a helper function to delete the bad jobs from mirror list and call it directly *before* the job's fence is signaled Changes in v2: - delete the useless list node check - also delete bad jobs in drm_sched_main because: kthread_unpark(ring->sched.thread) will be invoked very early before amdgpu_device_gpu_recover's return, then drm_sched_main will have chance to pick up a new job from the job queue. This new job will be added into the mirror list and processed by amdgpu_job_run, but may not be deleted from the mirror list on time due to the same reason. And finally re-processed by drm_sched_job_recovery Signed-off-by: Trigger Huang Reviewed-by: Christian König Signed-off-by: Alex Deucher --- drivers/gpu/drm/scheduler/sched_main.c | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) (limited to 'drivers/gpu/drm') diff --git a/drivers/gpu/drm/scheduler/sched_main.c b/drivers/gpu/drm/scheduler/sched_main.c index 18ebbb05762e..6fedf9544bbf 100644 --- a/drivers/gpu/drm/scheduler/sched_main.c +++ b/drivers/gpu/drm/scheduler/sched_main.c @@ -60,6 +60,8 @@ static void drm_sched_process_job(struct dma_fence *f, struct dma_fence_cb *cb); +static void drm_sched_expel_job_unlocked(struct drm_sched_job *s_job); + /** * drm_sched_rq_init - initialize a given run queue struct * @@ -228,7 +230,7 @@ static void drm_sched_job_finish(struct work_struct *work) spin_lock(&sched->job_list_lock); /* remove job from ring_mirror_list */ - list_del(&s_job->node); + list_del_init(&s_job->node); /* queue TDR for next job */ drm_sched_start_timeout(sched); spin_unlock(&sched->job_list_lock); @@ -391,6 +393,8 @@ void drm_sched_job_recovery(struct drm_gpu_scheduler *sched) r); dma_fence_put(fence); } else { + if (s_fence->finished.error < 0) + drm_sched_expel_job_unlocked(s_job); drm_sched_process_job(NULL, &s_fence->cb); } spin_lock(&sched->job_list_lock); @@ -595,6 +599,8 @@ static int drm_sched_main(void *param) r); dma_fence_put(fence); } else { + if (s_fence->finished.error < 0) + drm_sched_expel_job_unlocked(sched_job); drm_sched_process_job(NULL, &s_fence->cb); } @@ -603,6 +609,15 @@ static int drm_sched_main(void *param) return 0; } +static void drm_sched_expel_job_unlocked(struct drm_sched_job *s_job) +{ + struct drm_gpu_scheduler *sched = s_job->sched; + + spin_lock(&sched->job_list_lock); + list_del_init(&s_job->node); + spin_unlock(&sched->job_list_lock); +} + /** * drm_sched_init - Init a gpu scheduler instance * -- cgit v1.2.3 From ccce29abfe036967a0fa0f291acb9ea4f5595486 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Fri, 16 Nov 2018 13:22:38 -0500 Subject: drm/amdgpu/psp: use define rather than magic number for mode1 reset MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Use the define rather than hardcoded value. Acked-by: Christian König Reviewed-by: Huang Rui Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/psp_v3_1.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/gpu/drm') diff --git a/drivers/gpu/drm/amd/amdgpu/psp_v3_1.c b/drivers/gpu/drm/amd/amdgpu/psp_v3_1.c index 64c267f37d4b..7efb823dd3b1 100644 --- a/drivers/gpu/drm/amd/amdgpu/psp_v3_1.c +++ b/drivers/gpu/drm/amd/amdgpu/psp_v3_1.c @@ -590,7 +590,7 @@ static int psp_v3_1_mode1_reset(struct psp_context *psp) } /*send the mode 1 reset command*/ - WREG32(offset, 0x70000); + WREG32(offset, GFX_CTRL_CMD_ID_MODE1_RST); mdelay(1000); -- cgit v1.2.3 From 39e94569039b58b55eef9e18ad96d666293aea4f Mon Sep 17 00:00:00 2001 From: Brajeswar Ghosh Date: Mon, 19 Nov 2018 22:02:19 +0530 Subject: drivers/gpu/drm/amd/amdgpu/gfx_v8_0.c: Remove duplicate header Remove gca/gfx_8_0_enum.h which is included more than once Signed-off-by: Brajeswar Ghosh Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/gfx_v8_0.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers/gpu/drm') diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v8_0.c b/drivers/gpu/drm/amd/amdgpu/gfx_v8_0.c index cb066a8dccd7..77cac0e25623 100644 --- a/drivers/gpu/drm/amd/amdgpu/gfx_v8_0.c +++ b/drivers/gpu/drm/amd/amdgpu/gfx_v8_0.c @@ -44,7 +44,6 @@ #include "gca/gfx_8_0_d.h" #include "gca/gfx_8_0_enum.h" #include "gca/gfx_8_0_sh_mask.h" -#include "gca/gfx_8_0_enum.h" #include "dce/dce_10_0_d.h" #include "dce/dce_10_0_sh_mask.h" -- cgit v1.2.3 From 8830f26bcd3cf1ff07d9078cd310a534c03b6a10 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Fri, 2 Nov 2018 16:12:12 +0000 Subject: drm/i915: Prevent machine hang from Broxton's vtd w/a and error capture Since capturing the error state requires fiddling around with the GGTT to read arbitrary buffers and is itself run under stop_machine(), it deadlocks the machine (effectively a hard hang) when run in conjunction with Broxton's VTd workaround to serialize GGTT access. v2: Store the ERR_PTR in first_error so that the error can be reported to the user via sysfs. v3: Mention the quirk in dmesg (using info as per usual) Fixes: 0ef34ad6222a ("drm/i915: Serialize GTT/Aperture accesses on BXT") Signed-off-by: Chris Wilson Cc: Jon Bloomfield Cc: John Harrison Cc: Tvrtko Ursulin Cc: Joonas Lahtinen Cc: Daniel Vetter Reviewed-by: Joonas Lahtinen Link: https://patchwork.freedesktop.org/patch/msgid/20181102161232.17742-5-chris@chris-wilson.co.uk (cherry picked from commit fb6f0b64e455b207a636346588e65bf9598d30eb) Signed-off-by: Joonas Lahtinen --- drivers/gpu/drm/i915/i915_gem_gtt.c | 5 +++++ drivers/gpu/drm/i915/i915_gpu_error.c | 15 ++++++++++++++- drivers/gpu/drm/i915/i915_gpu_error.h | 8 +++++++- 3 files changed, 26 insertions(+), 2 deletions(-) (limited to 'drivers/gpu/drm') diff --git a/drivers/gpu/drm/i915/i915_gem_gtt.c b/drivers/gpu/drm/i915/i915_gem_gtt.c index 47c302543799..07999fe09ad2 100644 --- a/drivers/gpu/drm/i915/i915_gem_gtt.c +++ b/drivers/gpu/drm/i915/i915_gem_gtt.c @@ -3413,6 +3413,11 @@ static int gen8_gmch_probe(struct i915_ggtt *ggtt) ggtt->vm.insert_page = bxt_vtd_ggtt_insert_page__BKL; if (ggtt->vm.clear_range != nop_clear_range) ggtt->vm.clear_range = bxt_vtd_ggtt_clear_range__BKL; + + /* Prevent recursively calling stop_machine() and deadlocks. */ + dev_info(dev_priv->drm.dev, + "Disabling error capture for VT-d workaround\n"); + i915_disable_error_state(dev_priv, -ENODEV); } ggtt->invalidate = gen6_ggtt_invalidate; diff --git a/drivers/gpu/drm/i915/i915_gpu_error.c b/drivers/gpu/drm/i915/i915_gpu_error.c index 8762d17b6659..3eb33e000d6f 100644 --- a/drivers/gpu/drm/i915/i915_gpu_error.c +++ b/drivers/gpu/drm/i915/i915_gpu_error.c @@ -648,6 +648,9 @@ int i915_error_state_to_str(struct drm_i915_error_state_buf *m, return 0; } + if (IS_ERR(error)) + return PTR_ERR(error); + if (*error->error_msg) err_printf(m, "%s\n", error->error_msg); err_printf(m, "Kernel: " UTS_RELEASE "\n"); @@ -1859,6 +1862,7 @@ void i915_capture_error_state(struct drm_i915_private *i915, error = i915_capture_gpu_state(i915); if (!error) { DRM_DEBUG_DRIVER("out of memory, not capturing error state\n"); + i915_disable_error_state(i915, -ENOMEM); return; } @@ -1914,5 +1918,14 @@ void i915_reset_error_state(struct drm_i915_private *i915) i915->gpu_error.first_error = NULL; spin_unlock_irq(&i915->gpu_error.lock); - i915_gpu_state_put(error); + if (!IS_ERR(error)) + i915_gpu_state_put(error); +} + +void i915_disable_error_state(struct drm_i915_private *i915, int err) +{ + spin_lock_irq(&i915->gpu_error.lock); + if (!i915->gpu_error.first_error) + i915->gpu_error.first_error = ERR_PTR(err); + spin_unlock_irq(&i915->gpu_error.lock); } diff --git a/drivers/gpu/drm/i915/i915_gpu_error.h b/drivers/gpu/drm/i915/i915_gpu_error.h index 8710fb18ed74..3ec89a504de5 100644 --- a/drivers/gpu/drm/i915/i915_gpu_error.h +++ b/drivers/gpu/drm/i915/i915_gpu_error.h @@ -343,6 +343,7 @@ static inline void i915_gpu_state_put(struct i915_gpu_state *gpu) struct i915_gpu_state *i915_first_error_state(struct drm_i915_private *i915); void i915_reset_error_state(struct drm_i915_private *i915); +void i915_disable_error_state(struct drm_i915_private *i915, int err); #else @@ -355,13 +356,18 @@ static inline void i915_capture_error_state(struct drm_i915_private *dev_priv, static inline struct i915_gpu_state * i915_first_error_state(struct drm_i915_private *i915) { - return NULL; + return ERR_PTR(-ENODEV); } static inline void i915_reset_error_state(struct drm_i915_private *i915) { } +static inline void i915_disable_error_state(struct drm_i915_private *i915, + int err) +{ +} + #endif /* IS_ENABLED(CONFIG_DRM_I915_CAPTURE_ERROR) */ #endif /* _I915_GPU_ERROR_H_ */ -- cgit v1.2.3 From ea6b13e9fed0fda9532ee04d38ed1bef1edbfdbf Mon Sep 17 00:00:00 2001 From: Fabrizio Castro Date: Mon, 19 Nov 2018 13:26:18 +0000 Subject: drm/bridge/sii902x: Add missing dependency on I2C_MUX kbuild test robot reports: >> ERROR: "i2c_mux_add_adapter" [drivers/gpu/drm/bridge/sii902x.ko] undefined! >> ERROR: "i2c_mux_alloc" [drivers/gpu/drm/bridge/sii902x.ko] undefined! >> ERROR: "i2c_mux_del_adapters" [drivers/gpu/drm/bridge/sii902x.ko] undefined! Quite obviously the driver depends on I2C_MUX, but adding a "depends on" introduces a recursive dependency, therefore this patch selects I2C_MUX instead. Fixes: 21d808405fe4 ("drm/bridge/sii902x: Fix EDID readback") Signed-off-by: Fabrizio Castro Link: https://lists.01.org/pipermail/kbuild-all/2018-November/054924.html Acked-by: Peter Rosin Signed-off-by: Boris Brezillon Link: https://patchwork.freedesktop.org/patch/msgid/1542633978-22064-1-git-send-email-fabrizio.castro@bp.renesas.com --- drivers/gpu/drm/bridge/Kconfig | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/gpu/drm') diff --git a/drivers/gpu/drm/bridge/Kconfig b/drivers/gpu/drm/bridge/Kconfig index 9eeb8ef0b174..2fee47b0d50b 100644 --- a/drivers/gpu/drm/bridge/Kconfig +++ b/drivers/gpu/drm/bridge/Kconfig @@ -95,6 +95,7 @@ config DRM_SII902X depends on OF select DRM_KMS_HELPER select REGMAP_I2C + select I2C_MUX ---help--- Silicon Image sii902x bridge chip driver. -- cgit v1.2.3 From f577f7eac5ad19eb1455acd2ec22aeb5f6a40ba0 Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Tue, 6 Nov 2018 15:40:22 +0000 Subject: drm/panel: s6d16d0: fix spelling mistake "enble" -> "enable" Trivial fix to spelling mistake in DRM_DEV_ERROR error message Signed-off-by: Colin Ian King Signed-off-by: Linus Walleij Link: https://patchwork.freedesktop.org/patch/msgid/20181106154022.9209-1-colin.king@canonical.com --- drivers/gpu/drm/panel/panel-samsung-s6d16d0.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/gpu/drm') diff --git a/drivers/gpu/drm/panel/panel-samsung-s6d16d0.c b/drivers/gpu/drm/panel/panel-samsung-s6d16d0.c index fa8bfa7c492d..33c22ee036f8 100644 --- a/drivers/gpu/drm/panel/panel-samsung-s6d16d0.c +++ b/drivers/gpu/drm/panel/panel-samsung-s6d16d0.c @@ -96,7 +96,7 @@ static int s6d16d0_prepare(struct drm_panel *panel) ret = mipi_dsi_dcs_set_tear_on(dsi, MIPI_DSI_DCS_TEAR_MODE_VBLANK); if (ret) { - DRM_DEV_ERROR(s6->dev, "failed to enble vblank TE (%d)\n", + DRM_DEV_ERROR(s6->dev, "failed to enable vblank TE (%d)\n", ret); return ret; } -- cgit v1.2.3 From f001488112c43fea6b7558e15f71d64ee7495286 Mon Sep 17 00:00:00 2001 From: Noralf Trønnes Date: Sat, 10 Nov 2018 15:56:43 +0100 Subject: drm/driver: Add defaults for .gem_prime_export/import callbacks MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The majority of drivers use drm_gem_prime_export() and drm_gem_prime_import() for these callbacks so let's make them the default. Signed-off-by: Noralf Trønnes Acked-by: Daniel Vetter Acked-by: Christian König Link: https://patchwork.freedesktop.org/patch/msgid/20181110145647.17580-2-noralf@tronnes.org --- Documentation/gpu/todo.rst | 7 +++++++ drivers/gpu/drm/drm_prime.c | 10 ++++++++-- include/drm/drm_drv.h | 4 ++++ 3 files changed, 19 insertions(+), 2 deletions(-) (limited to 'drivers/gpu/drm') diff --git a/Documentation/gpu/todo.rst b/Documentation/gpu/todo.rst index 5c9d86c962af..abc31956ef15 100644 --- a/Documentation/gpu/todo.rst +++ b/Documentation/gpu/todo.rst @@ -234,6 +234,13 @@ efficient. Contact: Daniel Vetter +Defaults for .gem_prime_import and export +----------------------------------------- + +Most drivers don't need to set drm_driver->gem_prime_import and +->gem_prime_export now that drm_gem_prime_import() and drm_gem_prime_export() +are the default. + Core refactorings ================= diff --git a/drivers/gpu/drm/drm_prime.c b/drivers/gpu/drm/drm_prime.c index 8d54d51a6b6b..ba6c7e02a2ae 100644 --- a/drivers/gpu/drm/drm_prime.c +++ b/drivers/gpu/drm/drm_prime.c @@ -529,7 +529,10 @@ static struct dma_buf *export_and_register_object(struct drm_device *dev, return dmabuf; } - dmabuf = dev->driver->gem_prime_export(dev, obj, flags); + if (dev->driver->gem_prime_export) + dmabuf = dev->driver->gem_prime_export(dev, obj, flags); + else + dmabuf = drm_gem_prime_export(dev, obj, flags); if (IS_ERR(dmabuf)) { /* normally the created dma-buf takes ownership of the ref, * but if that fails then drop the ref @@ -762,7 +765,10 @@ int drm_gem_prime_fd_to_handle(struct drm_device *dev, /* never seen this one, need to import */ mutex_lock(&dev->object_name_lock); - obj = dev->driver->gem_prime_import(dev, dma_buf); + if (dev->driver->gem_prime_import) + obj = dev->driver->gem_prime_import(dev, dma_buf); + else + obj = drm_gem_prime_import(dev, dma_buf); if (IS_ERR(obj)) { ret = PTR_ERR(obj); goto out_unlock; diff --git a/include/drm/drm_drv.h b/include/drm/drm_drv.h index 3199ef70c007..dbb2f6ad184a 100644 --- a/include/drm/drm_drv.h +++ b/include/drm/drm_drv.h @@ -471,6 +471,8 @@ struct drm_driver { * @gem_prime_export: * * export GEM -> dmabuf + * + * This defaults to drm_gem_prime_export() if not set. */ struct dma_buf * (*gem_prime_export)(struct drm_device *dev, struct drm_gem_object *obj, int flags); @@ -478,6 +480,8 @@ struct drm_driver { * @gem_prime_import: * * import dmabuf -> GEM + * + * This defaults to drm_gem_prime_import() if not set. */ struct drm_gem_object * (*gem_prime_import)(struct drm_device *dev, struct dma_buf *dma_buf); -- cgit v1.2.3 From 7698799f9554deeb0f3abb22857c3deb41c10db8 Mon Sep 17 00:00:00 2001 From: Noralf Trønnes Date: Sat, 10 Nov 2018 15:56:44 +0100 Subject: drm/prime: Add drm_gem_prime_mmap() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add a generic PRIME GEM mmap function. v2: Fix link in docs (Daniel Vetter) Suggested-by: Daniel Vetter Signed-off-by: Noralf Trønnes Reviewed-by: Daniel Vetter Acked-by: Christian König Link: https://patchwork.freedesktop.org/patch/msgid/20181110145647.17580-3-noralf@tronnes.org --- drivers/gpu/drm/drm_prime.c | 37 +++++++++++++++++++++++++++++++++++++ include/drm/drm_prime.h | 1 + 2 files changed, 38 insertions(+) (limited to 'drivers/gpu/drm') diff --git a/drivers/gpu/drm/drm_prime.c b/drivers/gpu/drm/drm_prime.c index ba6c7e02a2ae..6a4fe0216e27 100644 --- a/drivers/gpu/drm/drm_prime.c +++ b/drivers/gpu/drm/drm_prime.c @@ -651,6 +651,43 @@ out_unlock: } EXPORT_SYMBOL(drm_gem_prime_handle_to_fd); +/** + * drm_gem_prime_mmap - PRIME mmap function for GEM drivers + * @obj: GEM object + * @vma: Virtual address range + * + * This function sets up a userspace mapping for PRIME exported buffers using + * the same codepath that is used for regular GEM buffer mapping on the DRM fd. + * The fake GEM offset is added to vma->vm_pgoff and &drm_driver->fops->mmap is + * called to set up the mapping. + * + * Drivers can use this as their &drm_driver.gem_prime_mmap callback. + */ +int drm_gem_prime_mmap(struct drm_gem_object *obj, struct vm_area_struct *vma) +{ + /* Used by drm_gem_mmap() to lookup the GEM object */ + struct drm_file priv = { + .minor = obj->dev->primary, + }; + struct file fil = { + .private_data = &priv, + }; + int ret; + + ret = drm_vma_node_allow(&obj->vma_node, &priv); + if (ret) + return ret; + + vma->vm_pgoff += drm_vma_node_start(&obj->vma_node); + + ret = obj->dev->driver->fops->mmap(&fil, vma); + + drm_vma_node_revoke(&obj->vma_node, &priv); + + return ret; +} +EXPORT_SYMBOL(drm_gem_prime_mmap); + /** * drm_gem_prime_import_dev - core implementation of the import callback * @dev: drm_device to import into diff --git a/include/drm/drm_prime.h b/include/drm/drm_prime.h index e2032fbc0f08..b03731a3f079 100644 --- a/include/drm/drm_prime.h +++ b/include/drm/drm_prime.h @@ -70,6 +70,7 @@ struct dma_buf *drm_gem_prime_export(struct drm_device *dev, int drm_gem_prime_handle_to_fd(struct drm_device *dev, struct drm_file *file_priv, uint32_t handle, uint32_t flags, int *prime_fd); +int drm_gem_prime_mmap(struct drm_gem_object *obj, struct vm_area_struct *vma); struct drm_gem_object *drm_gem_prime_import(struct drm_device *dev, struct dma_buf *dma_buf); -- cgit v1.2.3 From b39b5394fabc79acbaafb26b777fd348c868bf7e Mon Sep 17 00:00:00 2001 From: Noralf Trønnes Date: Sat, 10 Nov 2018 15:56:45 +0100 Subject: drm/gem: Add drm_gem_object_funcs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This adds an optional function table on GEM objects. The main benefit is for drivers that support more than one type of memory (shmem,vram,cma) for their buffers depending on the hardware it runs on. With the callbacks attached to the GEM object itself, it is easier to have core helpers for the the various buffer types. The driver only has to make the decision about buffer type on GEM object creation and all other callbacks can be handled by the chosen helper. drm_driver->gem_prime_res_obj has not been added since there's a todo to put a reservation_object into drm_gem_object. v3: Add todo entry v2: Drop drm_gem_object_funcs->prime_mmap in favour of drm_gem_prime_mmap() (Daniel Vetter) v1: - drm_gem_object_funcs.map -> .prime_map let it only do PRIME mmap like the function it superseeds (Daniel Vetter) - Flip around the if ladders and make obj->funcs the first choice highlighting the fact that this the new default way of doing it (Daniel Vetter) Signed-off-by: Noralf Trønnes Acked-by: Daniel Vetter Acked-by: Christian König Link: https://patchwork.freedesktop.org/patch/msgid/20181110145647.17580-4-noralf@tronnes.org --- Documentation/gpu/todo.rst | 6 ++ drivers/gpu/drm/drm_client.c | 12 ++-- drivers/gpu/drm/drm_gem.c | 109 ++++++++++++++++++++++++++++++++--- drivers/gpu/drm/drm_prime.c | 34 ++++++----- include/drm/drm_gem.h | 131 +++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 258 insertions(+), 34 deletions(-) (limited to 'drivers/gpu/drm') diff --git a/Documentation/gpu/todo.rst b/Documentation/gpu/todo.rst index abc31956ef15..31ef4adc91c9 100644 --- a/Documentation/gpu/todo.rst +++ b/Documentation/gpu/todo.rst @@ -241,6 +241,12 @@ Most drivers don't need to set drm_driver->gem_prime_import and ->gem_prime_export now that drm_gem_prime_import() and drm_gem_prime_export() are the default. +struct drm_gem_object_funcs +--------------------------- + +GEM objects can now have a function table instead of having the callbacks on the +DRM driver struct. This is now the preferred way and drivers can be moved over. + Core refactorings ================= diff --git a/drivers/gpu/drm/drm_client.c b/drivers/gpu/drm/drm_client.c index fc03d26fcacc..9b2bd28dde0a 100644 --- a/drivers/gpu/drm/drm_client.c +++ b/drivers/gpu/drm/drm_client.c @@ -81,8 +81,7 @@ int drm_client_init(struct drm_device *dev, struct drm_client_dev *client, { int ret; - if (!drm_core_check_feature(dev, DRIVER_MODESET) || - !dev->driver->dumb_create || !dev->driver->gem_prime_vmap) + if (!drm_core_check_feature(dev, DRIVER_MODESET) || !dev->driver->dumb_create) return -EOPNOTSUPP; if (funcs && !try_module_get(funcs->owner)) @@ -229,8 +228,7 @@ static void drm_client_buffer_delete(struct drm_client_buffer *buffer) { struct drm_device *dev = buffer->client->dev; - if (buffer->vaddr && dev->driver->gem_prime_vunmap) - dev->driver->gem_prime_vunmap(buffer->gem, buffer->vaddr); + drm_gem_vunmap(buffer->gem, buffer->vaddr); if (buffer->gem) drm_gem_object_put_unlocked(buffer->gem); @@ -283,9 +281,9 @@ drm_client_buffer_create(struct drm_client_dev *client, u32 width, u32 height, u * fd_install step out of the driver backend hooks, to make that * final step optional for internal users. */ - vaddr = dev->driver->gem_prime_vmap(obj); - if (!vaddr) { - ret = -ENOMEM; + vaddr = drm_gem_vmap(obj); + if (IS_ERR(vaddr)) { + ret = PTR_ERR(vaddr); goto err_delete; } diff --git a/drivers/gpu/drm/drm_gem.c b/drivers/gpu/drm/drm_gem.c index 512078ebd97b..8b55ece97967 100644 --- a/drivers/gpu/drm/drm_gem.c +++ b/drivers/gpu/drm/drm_gem.c @@ -257,7 +257,9 @@ drm_gem_object_release_handle(int id, void *ptr, void *data) struct drm_gem_object *obj = ptr; struct drm_device *dev = obj->dev; - if (dev->driver->gem_close_object) + if (obj->funcs && obj->funcs->close) + obj->funcs->close(obj, file_priv); + else if (dev->driver->gem_close_object) dev->driver->gem_close_object(obj, file_priv); if (drm_core_check_feature(dev, DRIVER_PRIME)) @@ -410,7 +412,11 @@ drm_gem_handle_create_tail(struct drm_file *file_priv, if (ret) goto err_remove; - if (dev->driver->gem_open_object) { + if (obj->funcs && obj->funcs->open) { + ret = obj->funcs->open(obj, file_priv); + if (ret) + goto err_revoke; + } else if (dev->driver->gem_open_object) { ret = dev->driver->gem_open_object(obj, file_priv); if (ret) goto err_revoke; @@ -835,7 +841,9 @@ drm_gem_object_free(struct kref *kref) container_of(kref, struct drm_gem_object, refcount); struct drm_device *dev = obj->dev; - if (dev->driver->gem_free_object_unlocked) { + if (obj->funcs) { + obj->funcs->free(obj); + } else if (dev->driver->gem_free_object_unlocked) { dev->driver->gem_free_object_unlocked(obj); } else if (dev->driver->gem_free_object) { WARN_ON(!mutex_is_locked(&dev->struct_mutex)); @@ -864,13 +872,13 @@ drm_gem_object_put_unlocked(struct drm_gem_object *obj) dev = obj->dev; - if (dev->driver->gem_free_object_unlocked) { - kref_put(&obj->refcount, drm_gem_object_free); - } else { + if (dev->driver->gem_free_object) { might_lock(&dev->struct_mutex); if (kref_put_mutex(&obj->refcount, drm_gem_object_free, &dev->struct_mutex)) mutex_unlock(&dev->struct_mutex); + } else { + kref_put(&obj->refcount, drm_gem_object_free); } } EXPORT_SYMBOL(drm_gem_object_put_unlocked); @@ -960,11 +968,14 @@ int drm_gem_mmap_obj(struct drm_gem_object *obj, unsigned long obj_size, if (obj_size < vma->vm_end - vma->vm_start) return -EINVAL; - if (!dev->driver->gem_vm_ops) + if (obj->funcs && obj->funcs->vm_ops) + vma->vm_ops = obj->funcs->vm_ops; + else if (dev->driver->gem_vm_ops) + vma->vm_ops = dev->driver->gem_vm_ops; + else return -EINVAL; vma->vm_flags |= VM_IO | VM_PFNMAP | VM_DONTEXPAND | VM_DONTDUMP; - vma->vm_ops = dev->driver->gem_vm_ops; vma->vm_private_data = obj; vma->vm_page_prot = pgprot_writecombine(vm_get_page_prot(vma->vm_flags)); vma->vm_page_prot = pgprot_decrypted(vma->vm_page_prot); @@ -1066,6 +1077,86 @@ void drm_gem_print_info(struct drm_printer *p, unsigned int indent, drm_printf_indent(p, indent, "imported=%s\n", obj->import_attach ? "yes" : "no"); - if (obj->dev->driver->gem_print_info) + if (obj->funcs && obj->funcs->print_info) + obj->funcs->print_info(p, indent, obj); + else if (obj->dev->driver->gem_print_info) obj->dev->driver->gem_print_info(p, indent, obj); } + +/** + * drm_gem_pin - Pin backing buffer in memory + * @obj: GEM object + * + * Make sure the backing buffer is pinned in memory. + * + * Returns: + * 0 on success or a negative error code on failure. + */ +int drm_gem_pin(struct drm_gem_object *obj) +{ + if (obj->funcs && obj->funcs->pin) + return obj->funcs->pin(obj); + else if (obj->dev->driver->gem_prime_pin) + return obj->dev->driver->gem_prime_pin(obj); + else + return 0; +} +EXPORT_SYMBOL(drm_gem_pin); + +/** + * drm_gem_unpin - Unpin backing buffer from memory + * @obj: GEM object + * + * Relax the requirement that the backing buffer is pinned in memory. + */ +void drm_gem_unpin(struct drm_gem_object *obj) +{ + if (obj->funcs && obj->funcs->unpin) + obj->funcs->unpin(obj); + else if (obj->dev->driver->gem_prime_unpin) + obj->dev->driver->gem_prime_unpin(obj); +} +EXPORT_SYMBOL(drm_gem_unpin); + +/** + * drm_gem_vmap - Map buffer into kernel virtual address space + * @obj: GEM object + * + * Returns: + * A virtual pointer to a newly created GEM object or an ERR_PTR-encoded negative + * error code on failure. + */ +void *drm_gem_vmap(struct drm_gem_object *obj) +{ + void *vaddr; + + if (obj->funcs && obj->funcs->vmap) + vaddr = obj->funcs->vmap(obj); + else if (obj->dev->driver->gem_prime_vmap) + vaddr = obj->dev->driver->gem_prime_vmap(obj); + else + vaddr = ERR_PTR(-EOPNOTSUPP); + + if (!vaddr) + vaddr = ERR_PTR(-ENOMEM); + + return vaddr; +} +EXPORT_SYMBOL(drm_gem_vmap); + +/** + * drm_gem_vunmap - Remove buffer mapping from kernel virtual address space + * @obj: GEM object + * @vaddr: Virtual address (can be NULL) + */ +void drm_gem_vunmap(struct drm_gem_object *obj, void *vaddr) +{ + if (!vaddr) + return; + + if (obj->funcs && obj->funcs->vunmap) + obj->funcs->vunmap(obj, vaddr); + else if (obj->dev->driver->gem_prime_vunmap) + obj->dev->driver->gem_prime_vunmap(obj, vaddr); +} +EXPORT_SYMBOL(drm_gem_vunmap); diff --git a/drivers/gpu/drm/drm_prime.c b/drivers/gpu/drm/drm_prime.c index 6a4fe0216e27..5737cb8c6f03 100644 --- a/drivers/gpu/drm/drm_prime.c +++ b/drivers/gpu/drm/drm_prime.c @@ -199,7 +199,6 @@ int drm_gem_map_attach(struct dma_buf *dma_buf, { struct drm_prime_attachment *prime_attach; struct drm_gem_object *obj = dma_buf->priv; - struct drm_device *dev = obj->dev; prime_attach = kzalloc(sizeof(*prime_attach), GFP_KERNEL); if (!prime_attach) @@ -208,10 +207,7 @@ int drm_gem_map_attach(struct dma_buf *dma_buf, prime_attach->dir = DMA_NONE; attach->priv = prime_attach; - if (!dev->driver->gem_prime_pin) - return 0; - - return dev->driver->gem_prime_pin(obj); + return drm_gem_pin(obj); } EXPORT_SYMBOL(drm_gem_map_attach); @@ -228,7 +224,6 @@ void drm_gem_map_detach(struct dma_buf *dma_buf, { struct drm_prime_attachment *prime_attach = attach->priv; struct drm_gem_object *obj = dma_buf->priv; - struct drm_device *dev = obj->dev; if (prime_attach) { struct sg_table *sgt = prime_attach->sgt; @@ -247,8 +242,7 @@ void drm_gem_map_detach(struct dma_buf *dma_buf, attach->priv = NULL; } - if (dev->driver->gem_prime_unpin) - dev->driver->gem_prime_unpin(obj); + drm_gem_unpin(obj); } EXPORT_SYMBOL(drm_gem_map_detach); @@ -310,7 +304,10 @@ struct sg_table *drm_gem_map_dma_buf(struct dma_buf_attachment *attach, if (WARN_ON(prime_attach->dir != DMA_NONE)) return ERR_PTR(-EBUSY); - sgt = obj->dev->driver->gem_prime_get_sg_table(obj); + if (obj->funcs) + sgt = obj->funcs->get_sg_table(obj); + else + sgt = obj->dev->driver->gem_prime_get_sg_table(obj); if (!IS_ERR(sgt)) { if (!dma_map_sg_attrs(attach->dev, sgt->sgl, sgt->nents, dir, @@ -406,12 +403,13 @@ EXPORT_SYMBOL(drm_gem_dmabuf_release); void *drm_gem_dmabuf_vmap(struct dma_buf *dma_buf) { struct drm_gem_object *obj = dma_buf->priv; - struct drm_device *dev = obj->dev; + void *vaddr; - if (dev->driver->gem_prime_vmap) - return dev->driver->gem_prime_vmap(obj); - else - return NULL; + vaddr = drm_gem_vmap(obj); + if (IS_ERR(vaddr)) + vaddr = NULL; + + return vaddr; } EXPORT_SYMBOL(drm_gem_dmabuf_vmap); @@ -426,10 +424,8 @@ EXPORT_SYMBOL(drm_gem_dmabuf_vmap); void drm_gem_dmabuf_vunmap(struct dma_buf *dma_buf, void *vaddr) { struct drm_gem_object *obj = dma_buf->priv; - struct drm_device *dev = obj->dev; - if (dev->driver->gem_prime_vunmap) - dev->driver->gem_prime_vunmap(obj, vaddr); + drm_gem_vunmap(obj, vaddr); } EXPORT_SYMBOL(drm_gem_dmabuf_vunmap); @@ -529,7 +525,9 @@ static struct dma_buf *export_and_register_object(struct drm_device *dev, return dmabuf; } - if (dev->driver->gem_prime_export) + if (obj->funcs && obj->funcs->export) + dmabuf = obj->funcs->export(obj, flags); + else if (dev->driver->gem_prime_export) dmabuf = dev->driver->gem_prime_export(dev, obj, flags); else dmabuf = drm_gem_prime_export(dev, obj, flags); diff --git a/include/drm/drm_gem.h b/include/drm/drm_gem.h index 3583b98a1718..f466ce5bde0e 100644 --- a/include/drm/drm_gem.h +++ b/include/drm/drm_gem.h @@ -38,6 +38,121 @@ #include +struct drm_gem_object; + +/** + * struct drm_gem_object_funcs - GEM object functions + */ +struct drm_gem_object_funcs { + /** + * @free: + * + * Deconstructor for drm_gem_objects. + * + * This callback is mandatory. + */ + void (*free)(struct drm_gem_object *obj); + + /** + * @open: + * + * Called upon GEM handle creation. + * + * This callback is optional. + */ + int (*open)(struct drm_gem_object *obj, struct drm_file *file); + + /** + * @close: + * + * Called upon GEM handle release. + * + * This callback is optional. + */ + void (*close)(struct drm_gem_object *obj, struct drm_file *file); + + /** + * @print_info: + * + * If driver subclasses struct &drm_gem_object, it can implement this + * optional hook for printing additional driver specific info. + * + * drm_printf_indent() should be used in the callback passing it the + * indent argument. + * + * This callback is called from drm_gem_print_info(). + * + * This callback is optional. + */ + void (*print_info)(struct drm_printer *p, unsigned int indent, + const struct drm_gem_object *obj); + + /** + * @export: + * + * Export backing buffer as a &dma_buf. + * If this is not set drm_gem_prime_export() is used. + * + * This callback is optional. + */ + struct dma_buf *(*export)(struct drm_gem_object *obj, int flags); + + /** + * @pin: + * + * Pin backing buffer in memory. + * + * This callback is optional. + */ + int (*pin)(struct drm_gem_object *obj); + + /** + * @unpin: + * + * Unpin backing buffer. + * + * This callback is optional. + */ + void (*unpin)(struct drm_gem_object *obj); + + /** + * @get_sg_table: + * + * Returns a Scatter-Gather table representation of the buffer. + * Used when exporting a buffer. + * + * This callback is mandatory if buffer export is supported. + */ + struct sg_table *(*get_sg_table)(struct drm_gem_object *obj); + + /** + * @vmap: + * + * Returns a virtual address for the buffer. + * + * This callback is optional. + */ + void *(*vmap)(struct drm_gem_object *obj); + + /** + * @vunmap: + * + * Releases the the address previously returned by @vmap. + * + * This callback is optional. + */ + void (*vunmap)(struct drm_gem_object *obj, void *vaddr); + + /** + * @vm_ops: + * + * Virtual memory operations used with mmap. + * + * This is optional but necessary for mmap support. + */ + const struct vm_operations_struct *vm_ops; +}; + /** * struct drm_gem_object - GEM buffer object * @@ -146,6 +261,17 @@ struct drm_gem_object { * simply leave it as NULL. */ struct dma_buf_attachment *import_attach; + + /** + * @funcs: + * + * Optional GEM object functions. If this is set, it will be used instead of the + * corresponding &drm_driver GEM callbacks. + * + * New drivers should use this. + * + */ + const struct drm_gem_object_funcs *funcs; }; /** @@ -293,4 +419,9 @@ int drm_gem_dumb_destroy(struct drm_file *file, struct drm_device *dev, uint32_t handle); +int drm_gem_pin(struct drm_gem_object *obj); +void drm_gem_unpin(struct drm_gem_object *obj); +void *drm_gem_vmap(struct drm_gem_object *obj); +void drm_gem_vunmap(struct drm_gem_object *obj, void *vaddr); + #endif /* __DRM_GEM_H__ */ -- cgit v1.2.3 From b9068cde51eea189c2c3560a9a8ae83f7b213c9c Mon Sep 17 00:00:00 2001 From: Noralf Trønnes Date: Sat, 10 Nov 2018 15:56:46 +0100 Subject: drm/cma-helper: Add DRM_GEM_CMA_VMAP_DRIVER_OPS MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This adds functionality to the CMA helper which ensures that the kernel virtual address is set on the CMA GEM object also for imported buffers. The drivers have been audited to ensure that none set ->vaddr on imported buffers, making the conditional dma_buf_vunmap() call in drm_gem_cma_free_object() safe. Signed-off-by: Noralf Trønnes Acked-by: Christian König Reviewed-by: Eric Anholt Link: https://patchwork.freedesktop.org/patch/msgid/20181110145647.17580-5-noralf@tronnes.org --- drivers/gpu/drm/drm_gem_cma_helper.c | 86 ++++++++++++++++++++++++++++++++++++ include/drm/drm_gem_cma_helper.h | 24 ++++++++++ 2 files changed, 110 insertions(+) (limited to 'drivers/gpu/drm') diff --git a/drivers/gpu/drm/drm_gem_cma_helper.c b/drivers/gpu/drm/drm_gem_cma_helper.c index 1d2ced882b66..cc26625b4b33 100644 --- a/drivers/gpu/drm/drm_gem_cma_helper.c +++ b/drivers/gpu/drm/drm_gem_cma_helper.c @@ -176,6 +176,7 @@ drm_gem_cma_create_with_handle(struct drm_file *file_priv, * * This function frees the backing memory of the CMA GEM object, cleans up the * GEM object state and frees the memory used to store the object itself. + * If the buffer is imported and the virtual address is set, it is released. * Drivers using the CMA helpers should set this as their * &drm_driver.gem_free_object_unlocked callback. */ @@ -189,6 +190,8 @@ void drm_gem_cma_free_object(struct drm_gem_object *gem_obj) dma_free_wc(gem_obj->dev->dev, cma_obj->base.size, cma_obj->vaddr, cma_obj->paddr); } else if (gem_obj->import_attach) { + if (cma_obj->vaddr) + dma_buf_vunmap(gem_obj->import_attach->dmabuf, cma_obj->vaddr); drm_prime_gem_destroy(gem_obj, cma_obj->sgt); } @@ -575,3 +578,86 @@ void drm_gem_cma_prime_vunmap(struct drm_gem_object *obj, void *vaddr) /* Nothing to do */ } EXPORT_SYMBOL_GPL(drm_gem_cma_prime_vunmap); + +static const struct drm_gem_object_funcs drm_cma_gem_default_funcs = { + .free = drm_gem_cma_free_object, + .print_info = drm_gem_cma_print_info, + .get_sg_table = drm_gem_cma_prime_get_sg_table, + .vmap = drm_gem_cma_prime_vmap, + .vm_ops = &drm_gem_cma_vm_ops, +}; + +/** + * drm_cma_gem_create_object_default_funcs - Create a CMA GEM object with a + * default function table + * @dev: DRM device + * @size: Size of the object to allocate + * + * This sets the GEM object functions to the default CMA helper functions. + * This function can be used as the &drm_driver.gem_create_object callback. + * + * Returns: + * A pointer to a allocated GEM object or an error pointer on failure. + */ +struct drm_gem_object * +drm_cma_gem_create_object_default_funcs(struct drm_device *dev, size_t size) +{ + struct drm_gem_cma_object *cma_obj; + + cma_obj = kzalloc(sizeof(*cma_obj), GFP_KERNEL); + if (!cma_obj) + return NULL; + + cma_obj->base.funcs = &drm_cma_gem_default_funcs; + + return &cma_obj->base; +} +EXPORT_SYMBOL(drm_cma_gem_create_object_default_funcs); + +/** + * drm_gem_cma_prime_import_sg_table_vmap - PRIME import another driver's + * scatter/gather table and get the virtual address of the buffer + * @dev: DRM device + * @attach: DMA-BUF attachment + * @sgt: Scatter/gather table of pinned pages + * + * This function imports a scatter/gather table using + * drm_gem_cma_prime_import_sg_table() and uses dma_buf_vmap() to get the kernel + * virtual address. This ensures that a CMA GEM object always has its virtual + * address set. This address is released when the object is freed. + * + * This function can be used as the &drm_driver.gem_prime_import_sg_table + * callback. The DRM_GEM_CMA_VMAP_DRIVER_OPS() macro provides a shortcut to set + * the necessary DRM driver operations. + * + * Returns: + * A pointer to a newly created GEM object or an ERR_PTR-encoded negative + * error code on failure. + */ +struct drm_gem_object * +drm_gem_cma_prime_import_sg_table_vmap(struct drm_device *dev, + struct dma_buf_attachment *attach, + struct sg_table *sgt) +{ + struct drm_gem_cma_object *cma_obj; + struct drm_gem_object *obj; + void *vaddr; + + vaddr = dma_buf_vmap(attach->dmabuf); + if (!vaddr) { + DRM_ERROR("Failed to vmap PRIME buffer\n"); + return ERR_PTR(-ENOMEM); + } + + obj = drm_gem_cma_prime_import_sg_table(dev, attach, sgt); + if (IS_ERR(obj)) { + dma_buf_vunmap(attach->dmabuf, vaddr); + return obj; + } + + cma_obj = to_drm_gem_cma_obj(obj); + cma_obj->vaddr = vaddr; + + return obj; +} +EXPORT_SYMBOL(drm_gem_cma_prime_import_sg_table_vmap); diff --git a/include/drm/drm_gem_cma_helper.h b/include/drm/drm_gem_cma_helper.h index 19777145cf8e..07c504940ba1 100644 --- a/include/drm/drm_gem_cma_helper.h +++ b/include/drm/drm_gem_cma_helper.h @@ -103,4 +103,28 @@ int drm_gem_cma_prime_mmap(struct drm_gem_object *obj, void *drm_gem_cma_prime_vmap(struct drm_gem_object *obj); void drm_gem_cma_prime_vunmap(struct drm_gem_object *obj, void *vaddr); +struct drm_gem_object * +drm_cma_gem_create_object_default_funcs(struct drm_device *dev, size_t size); + +/** + * DRM_GEM_CMA_VMAP_DRIVER_OPS - CMA GEM driver operations ensuring a virtual + * address on the buffer + * + * This macro provides a shortcut for setting the default GEM operations in the + * &drm_driver structure for drivers that need the virtual address also on + * imported buffers. + */ +#define DRM_GEM_CMA_VMAP_DRIVER_OPS \ + .gem_create_object = drm_cma_gem_create_object_default_funcs, \ + .dumb_create = drm_gem_cma_dumb_create, \ + .prime_handle_to_fd = drm_gem_prime_handle_to_fd, \ + .prime_fd_to_handle = drm_gem_prime_fd_to_handle, \ + .gem_prime_import_sg_table = drm_gem_cma_prime_import_sg_table_vmap, \ + .gem_prime_mmap = drm_gem_prime_mmap + +struct drm_gem_object * +drm_gem_cma_prime_import_sg_table_vmap(struct drm_device *drm, + struct dma_buf_attachment *attach, + struct sg_table *sgt); + #endif /* __DRM_GEM_CMA_HELPER_H__ */ -- cgit v1.2.3 From 3db8d37dd84e93f352b8a8d34a713415cd1a6d0f Mon Sep 17 00:00:00 2001 From: Noralf Trønnes Date: Sat, 10 Nov 2018 15:56:47 +0100 Subject: drm/tinydrm: Use DRM_GEM_CMA_VMAP_DRIVER_OPS MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The CMA helper now has the functionality to ensure a virtual address on imported buffer so use that. While touching all tinydrm drivers, remove the unnecessary inclusion of drm_fb_helper.h in some drivers. Cc: David Lechner Cc: Eric Anholt Signed-off-by: Noralf Trønnes Acked-by: Christian König Reviewed-by: Eric Anholt Link: https://patchwork.freedesktop.org/patch/msgid/20181110145647.17580-6-noralf@tronnes.org --- drivers/gpu/drm/tinydrm/core/tinydrm-core.c | 71 -------------------------- drivers/gpu/drm/tinydrm/core/tinydrm-helpers.c | 6 +++ drivers/gpu/drm/tinydrm/hx8357d.c | 4 +- drivers/gpu/drm/tinydrm/ili9225.c | 5 +- drivers/gpu/drm/tinydrm/ili9341.c | 4 +- drivers/gpu/drm/tinydrm/mi0283qt.c | 6 +-- drivers/gpu/drm/tinydrm/mipi-dbi.c | 10 ++-- drivers/gpu/drm/tinydrm/repaper.c | 4 +- drivers/gpu/drm/tinydrm/st7586.c | 5 +- drivers/gpu/drm/tinydrm/st7735r.c | 4 +- include/drm/tinydrm/tinydrm.h | 35 +++---------- 11 files changed, 38 insertions(+), 116 deletions(-) (limited to 'drivers/gpu/drm') diff --git a/drivers/gpu/drm/tinydrm/core/tinydrm-core.c b/drivers/gpu/drm/tinydrm/core/tinydrm-core.c index 9af51d982a33..01a6f2d42440 100644 --- a/drivers/gpu/drm/tinydrm/core/tinydrm-core.c +++ b/drivers/gpu/drm/tinydrm/core/tinydrm-core.c @@ -36,77 +36,6 @@ * and registers the DRM device using devm_tinydrm_register(). */ -/** - * tinydrm_gem_cma_prime_import_sg_table - Produce a CMA GEM object from - * another driver's scatter/gather table of pinned pages - * @drm: DRM device to import into - * @attach: DMA-BUF attachment - * @sgt: Scatter/gather table of pinned pages - * - * This function imports a scatter/gather table exported via DMA-BUF by - * another driver using drm_gem_cma_prime_import_sg_table(). It sets the - * kernel virtual address on the CMA object. Drivers should use this as their - * &drm_driver->gem_prime_import_sg_table callback if they need the virtual - * address. tinydrm_gem_cma_free_object() should be used in combination with - * this function. - * - * Returns: - * A pointer to a newly created GEM object or an ERR_PTR-encoded negative - * error code on failure. - */ -struct drm_gem_object * -tinydrm_gem_cma_prime_import_sg_table(struct drm_device *drm, - struct dma_buf_attachment *attach, - struct sg_table *sgt) -{ - struct drm_gem_cma_object *cma_obj; - struct drm_gem_object *obj; - void *vaddr; - - vaddr = dma_buf_vmap(attach->dmabuf); - if (!vaddr) { - DRM_ERROR("Failed to vmap PRIME buffer\n"); - return ERR_PTR(-ENOMEM); - } - - obj = drm_gem_cma_prime_import_sg_table(drm, attach, sgt); - if (IS_ERR(obj)) { - dma_buf_vunmap(attach->dmabuf, vaddr); - return obj; - } - - cma_obj = to_drm_gem_cma_obj(obj); - cma_obj->vaddr = vaddr; - - return obj; -} -EXPORT_SYMBOL(tinydrm_gem_cma_prime_import_sg_table); - -/** - * tinydrm_gem_cma_free_object - Free resources associated with a CMA GEM - * object - * @gem_obj: GEM object to free - * - * This function frees the backing memory of the CMA GEM object, cleans up the - * GEM object state and frees the memory used to store the object itself using - * drm_gem_cma_free_object(). It also handles PRIME buffers which has the kernel - * virtual address set by tinydrm_gem_cma_prime_import_sg_table(). Drivers - * can use this as their &drm_driver->gem_free_object_unlocked callback. - */ -void tinydrm_gem_cma_free_object(struct drm_gem_object *gem_obj) -{ - if (gem_obj->import_attach) { - struct drm_gem_cma_object *cma_obj; - - cma_obj = to_drm_gem_cma_obj(gem_obj); - dma_buf_vunmap(gem_obj->import_attach->dmabuf, cma_obj->vaddr); - cma_obj->vaddr = NULL; - } - - drm_gem_cma_free_object(gem_obj); -} -EXPORT_SYMBOL_GPL(tinydrm_gem_cma_free_object); - static struct drm_framebuffer * tinydrm_fb_create(struct drm_device *drm, struct drm_file *file_priv, const struct drm_mode_fb_cmd2 *mode_cmd) diff --git a/drivers/gpu/drm/tinydrm/core/tinydrm-helpers.c b/drivers/gpu/drm/tinydrm/core/tinydrm-helpers.c index dcd390163a4a..bf6bfbc5d412 100644 --- a/drivers/gpu/drm/tinydrm/core/tinydrm-helpers.c +++ b/drivers/gpu/drm/tinydrm/core/tinydrm-helpers.c @@ -9,12 +9,18 @@ #include #include +#include #include #include #include +#include +#include +#include +#include #include #include +#include static unsigned int spi_max; module_param(spi_max, uint, 0400); diff --git a/drivers/gpu/drm/tinydrm/hx8357d.c b/drivers/gpu/drm/tinydrm/hx8357d.c index c3e51c2baebc..81a2bbeb25d4 100644 --- a/drivers/gpu/drm/tinydrm/hx8357d.c +++ b/drivers/gpu/drm/tinydrm/hx8357d.c @@ -16,7 +16,7 @@ #include #include -#include +#include #include #include #include @@ -188,7 +188,7 @@ DEFINE_DRM_GEM_CMA_FOPS(hx8357d_fops); static struct drm_driver hx8357d_driver = { .driver_features = DRIVER_GEM | DRIVER_MODESET | DRIVER_PRIME | DRIVER_ATOMIC, .fops = &hx8357d_fops, - TINYDRM_GEM_DRIVER_OPS, + DRM_GEM_CMA_VMAP_DRIVER_OPS, .debugfs_init = mipi_dbi_debugfs_init, .name = "hx8357d", .desc = "HX8357D", diff --git a/drivers/gpu/drm/tinydrm/ili9225.c b/drivers/gpu/drm/tinydrm/ili9225.c index 455fefe012f5..78f7c2d1b449 100644 --- a/drivers/gpu/drm/tinydrm/ili9225.c +++ b/drivers/gpu/drm/tinydrm/ili9225.c @@ -20,7 +20,8 @@ #include #include